package com.jrx.anytxn.reporting.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jrx.anytxn.accounting.entity.GaVoucherInfo;
import com.jrx.anytxn.common.constant.CommonContants;
import com.jrx.anytxn.common.constant.Constants;
import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.TxnBizException;
import com.jrx.anytxn.common.exception.TxnException;
import com.jrx.anytxn.common.uitl.DateUtils;
import com.jrx.anytxn.common.uitl.SeqUtils;
import com.jrx.anytxn.common.uitl.StringUtils;
import com.jrx.anytxn.customer.constant.BankCardConstant;
import com.jrx.anytxn.customer.constant.CustomerConstant;
import com.jrx.anytxn.customer.entity.CmCustomerBankcardInfo;
import com.jrx.anytxn.customer.entity.CmCustomerExtInfo;
import com.jrx.anytxn.customer.entity.CmCustomerFirstLevel;
import com.jrx.anytxn.customer.entity.CmCustomerLimitInfo;
import com.jrx.anytxn.customer.entity.CmCustomerSecondLevel;
import com.jrx.anytxn.customer.entity.CmLimitChangeLog;
import com.jrx.anytxn.customer.mapper.ext.ExtCmCustomerBankcardInfoMapper;
import com.jrx.anytxn.customer.mapper.ext.ExtCmCustomerExtInfoMapper;
import com.jrx.anytxn.customer.mapper.ext.ExtCmCustomerFirstLevelMapper;
import com.jrx.anytxn.customer.mapper.ext.ExtCmCustomerLimitInfoMapper;
import com.jrx.anytxn.customer.service.ICustomerLimitInfoService;
import com.jrx.anytxn.customer.service.ICustomerService;
import com.jrx.anytxn.param.constant.Constant;
import com.jrx.anytxn.param.dto.system.SystemParameterRes;
import com.jrx.anytxn.param.entity.PrCreditLimitMapping;
import com.jrx.anytxn.param.entity.PrOrganizationTable;
import com.jrx.anytxn.param.entity.PrPenaltyRateTable;
import com.jrx.anytxn.param.entity.PrProductTable;
import com.jrx.anytxn.param.mapper.ext.ExtPrCreditLimitMappingMapper;
import com.jrx.anytxn.param.service.product.IPrPenaltyRateTableService;
import com.jrx.anytxn.param.service.product.IProductTableService;
import com.jrx.anytxn.param.service.system.IOrganizationTableService;
import com.jrx.anytxn.param.service.system.ISystemParameterService;
import com.jrx.anytxn.param.utils.BizTypeProducts;
import com.jrx.anytxn.reporting.constant.ReportingConstant;
import com.jrx.anytxn.reporting.entity.AmlIATrading;
import com.jrx.anytxn.reporting.entity.BdpInterfaceJob;
import com.jrx.anytxn.reporting.entity.CmInteCoAcctntEntryDtl;
import com.jrx.anytxn.reporting.entity.CmInteCoImpairmentInfo;
import com.jrx.anytxn.reporting.entity.CmInteCoLonInfo;
import com.jrx.anytxn.reporting.entity.CmInteCoLonInfoBean;
import com.jrx.anytxn.reporting.entity.CmInteCoLonInfoCi;
import com.jrx.anytxn.reporting.entity.CmInteCoLonRepayDtl;
import com.jrx.anytxn.reporting.entity.CmInteCoLonRepayDtlCi;
import com.jrx.anytxn.reporting.entity.CmInteCoLonRepayPlan;
import com.jrx.anytxn.reporting.entity.LimitChangeLogUpdate;
import com.jrx.anytxn.reporting.enums.PairingEnum;
import com.jrx.anytxn.reporting.enums.RepaymentEnum;
import com.jrx.anytxn.reporting.mapper.base.BdpInterfaceJobMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtAmlIATradingMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtBdpInterfaceJobMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtCmInteCoAcctntEntryDtlMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtCmInteCoCustInfoMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtCmInteCoImpairmentInfoMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtCmInteCoLonCrdtInfoMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtCmInteCoLonInfoMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtCmInteCoLonRepayDtlMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtCmInteCoLonRepayPlanMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtFtpInteCoLonMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtMEastVStzfxxbMapper;
import com.jrx.anytxn.reporting.mapper.ext.ExtTlFreeInterestTableMapper;
import com.jrx.anytxn.reporting.service.IXibService;
import com.jrx.anytxn.transaction.bean.DebtBean;
import com.jrx.anytxn.transaction.constant.TransBizConstant;
import com.jrx.anytxn.transaction.dto.loan.BillDetail;
import com.jrx.anytxn.transaction.dto.loan.BillDetailsInquiryReq;
import com.jrx.anytxn.transaction.dto.loan.BillDetailsInquiryRes;
import com.jrx.anytxn.transaction.entity.AmAccountMainInfo;
import com.jrx.anytxn.transaction.entity.AmDelinquencyInfo;
import com.jrx.anytxn.transaction.entity.AmInterestAccrualInfo;
import com.jrx.anytxn.transaction.entity.AmLoanAccountInfo;
import com.jrx.anytxn.transaction.entity.AmLoanMainInfo;
import com.jrx.anytxn.transaction.entity.AmLoanMainInfoVo;
import com.jrx.anytxn.transaction.entity.AmRepaymentPlanInfo;
import com.jrx.anytxn.transaction.entity.TlDisbursementLog;
import com.jrx.anytxn.transaction.entity.TlGlInterfaceInfo;
import com.jrx.anytxn.transaction.entity.TlInterestAccrualLog;
import com.jrx.anytxn.transaction.entity.TlPaymentAllocationLog;
import com.jrx.anytxn.transaction.entity.TlPaymentLog;
import com.jrx.anytxn.transaction.handler.ILoanHandler;
import com.jrx.anytxn.transaction.mapper.ext.ExtAmAccountMainInfoMapper;
import com.jrx.anytxn.transaction.mapper.ext.ExtAmDelinquencyInfoMapper;
import com.jrx.anytxn.transaction.mapper.ext.ExtAmInterestAccrualInfoMapper;
import com.jrx.anytxn.transaction.mapper.ext.ExtAmLoanAccountInfoMapper;
import com.jrx.anytxn.transaction.mapper.ext.ExtAmLoanMainInfoMapper;
import com.jrx.anytxn.transaction.mapper.ext.ExtAmRepaymentPlanInfoMapper;
import com.jrx.anytxn.transaction.mapper.ext.ExtTlDisbursementLogMapper;
import com.jrx.anytxn.transaction.mapper.ext.ExtTlGlInterfaceInfoMapper;
import com.jrx.anytxn.transaction.mapper.ext.ExtTlPaymentAllocationLogMapper;
import com.jrx.anytxn.transaction.mapper.ext.ExtTlPaymentLogMapper;
import com.jrx.anytxn.transaction.service.IDebtCalculationService;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class XibServiceImpl implements IXibService {

    private static final Logger logger = LoggerFactory.getLogger(XibServiceImpl.class);

    @Resource
    private IOrganizationTableService organizationTableService;
    @Resource
    private ExtAmLoanAccountInfoMapper extAmLoanAccountInfoMapper;
    @Resource
    private ExtAmLoanMainInfoMapper extAmLoanMainInfoMapper;
    @Resource
    private ExtCmCustomerLimitInfoMapper extCmCustomerLimitInfoMapper;
    @Resource
    private IProductTableService productTableService;
    @Resource
    private ExtAmDelinquencyInfoMapper extAmDelinquencyInfoMapper;
    @Resource
    private ExtCmCustomerBankcardInfoMapper extCmCustomerBankcardInfoMapper;
    @Resource
    private ExtAmRepaymentPlanInfoMapper extAmRepaymentPlanInfoMapper;
    @Resource
    private IPrPenaltyRateTableService prPenaltyRateTableService;
    @Resource
    private ExtTlPaymentLogMapper extTlPaymentLogMapper;
    @Resource
    private ExtTlPaymentAllocationLogMapper extTlPaymentAllocationLogMapper;
    @Resource
    private ICustomerService customerService;
    @Resource
    private ExtCmCustomerFirstLevelMapper extCmCustomerFirstLevelMapper;
    @Resource
    private IDebtCalculationService debtCalculationService;
    @Resource
    private ExtAmInterestAccrualInfoMapper extAmInterestAccrualInfoMapper;
    @Resource
    private ExtBdpInterfaceJobMapper extBdpInterfaceJobMapper;
    @Resource
    private ExtCmInteCoCustInfoMapper extCmInteCoCustInfoMapper;
    @Resource
    private BdpInterfaceJobMapper bdpInterfaceJobMapper;
    @Resource
    private ExtCmInteCoLonCrdtInfoMapper extCmInteCoLonCrdtInfoMapper;
    @Resource
    private ExtCmInteCoLonInfoMapper extCmInteCoLonInfoMapper;
    @Resource
    private ExtCmInteCoLonRepayPlanMapper extCmInteCoLonRepayPlanMapper;
    @Resource
    private ExtCmInteCoAcctntEntryDtlMapper extCmInteCoAcctntEntryDtlMapper;
    @Resource
    private ExtCmInteCoLonRepayDtlMapper extCmInteCoLonRepayDtlMapper;
    @Resource
    private ExtAmlIATradingMapper extAmlIATradingMapper;
    @Resource
    private ExtCmInteCoImpairmentInfoMapper extCmInteCoImpairmentInfoMapper;
    @Resource
    private ISystemParameterService systemParameterServiceImpl;
    @Resource
    private ExtTlFreeInterestTableMapper extTlFreeInterestTableMapper;
    @Resource
    private ExtFtpInteCoLonMapper extFtpInteCoLonMapper;
    @Resource
    private ExtMEastVStzfxxbMapper extMEastVStzfxxbMapper;
    @Resource
    private ILoanHandler loanHandler;
    @Resource
    private ExtAmAccountMainInfoMapper extAmAccountMainInfoMapper;
    @Resource
    ExtPrCreditLimitMappingMapper extPrCreditLimitMappingMapper;
    @Resource
    private ExtCmCustomerExtInfoMapper extCmCustomerExtInfoMapper;
    @Resource
    ICustomerLimitInfoService iCustomerLimitInfoService;
    @Resource
    ExtTlDisbursementLogMapper extTlDisbursementLogMapper;
    @Resource
    ExtTlGlInterfaceInfoMapper extTlGlInterfaceInfoMapper;

    private static String BIZ_CLASS_NAME_XAH = "数字消费-兴安花";
    private static String BIZ_CLASS_NAME_XAF = "数字消费-兴安付";
    private static String BIZ_CLASS_NAME_XAJ = "数字消费-兴安借";
    private static String PRODUCT_NO_XAH = "CCS-0200";
    private static String PRODUCT_NO_XAF = "CCS-0204";
    private static String PRODUCT_NO_XAJ = "CCS-0205";
    private static String PRODUCT_NAME_XAH = "兴安花";
    private static String PRODUCT_NAME_XAF = "兴安付";
    private static String PRODUCT_NAME_XAJ = "兴安借";

    @Override
    public CmInteCoLonInfoBean assemLoanInfo(CmCustomerFirstLevel firstLevel) throws TxnException {
        CmInteCoLonInfoBean bean = new CmInteCoLonInfoBean();
        //如果为空直接返回
        if (null == firstLevel) {
            return null;
        }
        //兴安花系列产品
        List<String> xahSeriesProducts = BizTypeProducts.getXAHSeriesProducts();
        String tenantId = firstLevel.getTenantId();
        String customerId = firstLevel.getCustomerId();
        //获取客户相关的所有额度编号，做集合运算  兴安花系列产品对应的额度列表
        List<String> xahSeriesLimitIds = extPrCreditLimitMappingMapper.selectLimitIdByTenIdAndProductIds(tenantId, xahSeriesProducts);
        if (xahSeriesLimitIds.isEmpty()) {
            logger.warn("assemLoanInfo|没有找到产品列表xahSeriesProducts：{}对应的LimitId", JSON.toJSONString(xahSeriesProducts));
            return null;
        }
        //获取当期业务时间
        PrOrganizationTable org = organizationTableService.findByOrId(TransBizConstant.DEFAULT_ORG_ID, tenantId);
        Date busiDate = org.getToday();
        String organizationId = org.getOrganizationId();
        // 获取用户"首笔贷款额度信息"
        CmLimitChangeLog firstLimitInfo = iCustomerLimitInfoService.queryFirstLimitChangeLog(tenantId, customerId, xahSeriesProducts);
        if (null == firstLimitInfo) {
            logger.info("没有查询到首次额度生效日期，客户id:{},机构id:{}", tenantId, customerId);
            return null;
        }
        Date eltSettleDate = firstLimitInfo.getEtlSettleDate();
        if (Objects.nonNull(eltSettleDate) && busiDate.compareTo(eltSettleDate) > 0) {
            logger.info("已经结清不需要再供数，客户id:{}", customerId);
            return null;
        }
        String etlContractNumber = firstLimitInfo.getEtlContractNumber();
        String etlLimitId = firstLimitInfo.getEtlLimitId();
        CmLimitChangeLog latestDateInfo = iCustomerLimitInfoService.queryLatestEtlEffectDate(tenantId, customerId, xahSeriesProducts);
        // 首笔借据取消，且没有其他借据
        boolean cancelFist = false;
        //统计客户订单查询
        Date etlEffectiveDate = latestDateInfo.getEtlEffectiveDate();
        AmLoanMainInfo countMain = extAmLoanMainInfoMapper.selectByCountCustomerWithProducts(customerId, tenantId, xahSeriesProducts, etlEffectiveDate);
        AmLoanAccountInfo countAcct = extAmLoanAccountInfoMapper.selectMaxLoanWithProducts(customerId, tenantId, xahSeriesProducts, etlEffectiveDate);
        if (null == countAcct) {
            countAcct = extAmLoanAccountInfoMapper.selectMinLoanInfo(customerId, tenantId, xahSeriesProducts, etlEffectiveDate);
            if (Objects.nonNull(countAcct)) {
                cancelFist = true;
                countMain = extAmLoanMainInfoMapper.selectMinInfo(customerId, tenantId, xahSeriesProducts, etlEffectiveDate);
                countAcct.setInterestBalance(BigDecimal.ZERO);
            } else {
                return null;
            }
        }
        String loanId = countAcct.getLoanId();


        AmLoanMainInfo mainInfo = extAmLoanMainInfoMapper.selectByLoanIdAndTenantId(loanId, tenantId);
        String channel = mainInfo.getChannel();
        //获取客户二级信息
        CmCustomerSecondLevel secondLevel = customerService.getSecondByChannelAndCustomerIdAndTensnId(channel, customerId, tenantId, mainInfo.getProductId());


        //获取当期还款日
        Date paymentDate = getCurrPaymentDate(busiDate);

        //获取产品信息
        PrProductTable pro = productTableService.findProByProIdAndOrgId(mainInfo.getProductId(), organizationId, tenantId);

        // 获取客户当前渠道默认扣款卡
        CmCustomerBankcardInfo bank = extCmCustomerBankcardInfoMapper.selectBankCardByCondition(
                customerId, TransBizConstant.Y_FLAG, null, channel, tenantId);

        //查询罚息累计账户
        BigDecimal lgPenInter = BigDecimal.ZERO;//累计罚息
        BigDecimal lgInter = BigDecimal.ZERO;//计提利息
        List<AmInterestAccrualInfo> amInterestAccrualInfoList = extAmInterestAccrualInfoMapper.selectByCustWithProducts(customerId, tenantId,
                Collections.singletonList(TransBizConstant.ACCOUNT_STATUS_1), xahSeriesProducts);
        if (CollectionUtils.isNotEmpty(amInterestAccrualInfoList)) {
            for (AmInterestAccrualInfo interestAccrualInfo : amInterestAccrualInfoList) {
                if (TransBizConstant.INTEREST_ACCRUAL_TYPE_10.equals(interestAccrualInfo.getAccountType())) {
                    lgPenInter = lgPenInter.add(interestAccrualInfo.getAccrualTotalAccruInterest());
                }
                if (TransBizConstant.INTEREST_ACCRUAL_TYPE_66.equals(interestAccrualInfo.getAccountType())) {
                    // 每个月9号需要特殊处理，ACCOUNT_STATUS会变成8-已完成计息
                    if (DateUtils.addDay(paymentDate, -1).equals(busiDate)) {
                        List<AmInterestAccrualInfo> list = extAmInterestAccrualInfoMapper.selectByCustWithProducts(customerId, tenantId,
                                Arrays.asList(TransBizConstant.ACCOUNT_STATUS_8), xahSeriesProducts);
                        if (CollectionUtils.isNotEmpty(list)) {
                            for (AmInterestAccrualInfo a : list) {
                                lgInter = lgInter.add(a.getAccrualTotalAccruInterest());
                            }
                        }
                    } else {
                        lgInter = lgInter.add(interestAccrualInfo.getAccrualTotalAccruInterest());
                    }
                }
            }
        }
        AmLoanMainInfo countMain2 = extAmLoanMainInfoMapper.selectByCountCustomer2WithProducts(customerId, tenantId, xahSeriesProducts);
        // 日利率和罚息利率取值是正常和逾期的最大值，如果查询不到，则默认值为0
        BigDecimal actualDailyRate = BigDecimal.ZERO;
        if (null != countMain2 && null != countMain2.getActualDailyRate()) {
            actualDailyRate = countMain2.getActualDailyRate();
        }
        //查询罚息利率参数 获取客户最大罚息利率
        BigDecimal penaltyRate = BigDecimal.ZERO;
        List<String> pemalteIdList = extAmLoanMainInfoMapper.selectDistinctPenaltyTableIdWithProducts(customerId, tenantId, xahSeriesProducts);
        if (CollectionUtils.isNotEmpty(pemalteIdList)) {
            for (String tableId : pemalteIdList) {
                PrPenaltyRateTable prPenaltyRateTable = prPenaltyRateTableService.findByPenaltyId(tableId, firstLevel.getOrganizationId(), tenantId);
                BigDecimal currTate = BigDecimal.ZERO;
                if (ReportingConstant.INCREASE_TYPE_0.equals(prPenaltyRateTable.getIncreaseType())) {
                    currTate = prPenaltyRateTable.getIncreaseNum();
                } else if (ReportingConstant.INCREASE_TYPE_1.equals(prPenaltyRateTable.getIncreaseType())) {
                    currTate = actualDailyRate.multiply(new BigDecimal(1).add(prPenaltyRateTable.getIncreaseNum()));
                }
                if (penaltyRate.compareTo(currTate) < 0) {
                    penaltyRate = currTate;
                }
            }
        }

        //查询客户逾期信息
        AmDelinquencyInfo amDelinquencyInfo = extAmDelinquencyInfoMapper.getMaxDelqDaysInfoWithProducts(customerId, tenantId, ReportingConstant.ACCOUNT_STATUS_1, xahSeriesProducts);

        //统计客户累计逾期几次
        int overNum = extAmDelinquencyInfoMapper.groupByCustomerIdWithProducts(customerId, tenantId, xahSeriesProducts, etlEffectiveDate);

        CmInteCoLonInfo cmInteCoLonInfo = new CmInteCoLonInfo();
        //1 ETL_DT 数据日期
        cmInteCoLonInfo.setEtlDt(busiDate);
        //2 LP_ORG_NO 法人机构标识
        cmInteCoLonInfo.setLpOrgNo("XIB");
        // 最早的一笔借据编号
        //String minLoanId = extAmLoanMainInfoMapper.selectMinLoanIdWithProducts(customerId, tenantId,xahSeriesProducts);
        String minLoanId = firstLimitInfo.getEtlLoanId();
        if (StringUtils.isBlank(minLoanId)) {
            minLoanId = loanId;
            buildUpdateLimitChangeLog(bean, tenantId, customerId, etlContractNumber, etlLimitId, null, null, loanId);
        }
        //3 DUBIL_NO 借据编号
        cmInteCoLonInfo.setDubilNo(minLoanId);
        //4 CUST_NO 客户编号
        cmInteCoLonInfo.setCustNo(customerId);
        //5 CORE_CUST_NO 核心客户号
        cmInteCoLonInfo.setCoreCustNo(firstLevel.getEcifId());
        //6 CUST_NAME 客户名称
        cmInteCoLonInfo.setCustName(firstLevel.getChineseName());
        //7 CONT_NO 合同编号
        cmInteCoLonInfo.setContNo(minLoanId);
        //8 CRDT_CONT_NO 授信合同编号
        cmInteCoLonInfo.setCrdtContNo(etlContractNumber);
        //9 LMT_NO 额度编号
        cmInteCoLonInfo.setLmtNo(etlLimitId);
        //10 SUBJECT_NO 科目编号
        cmInteCoLonInfo.setSubjectNo("11400301");
        //11 LEVEL5_CLASS_CD 五级分类代码
        //12 LEVEL5_CLASS_NAME 五级分类名称
        //13 LEVEL10_CLASS_CD 十级分类代码
        //14 LEVEL10_CLASS_NAME 十级分类名称
        //15 BIZ_CLASS_NO 业务分类编号
        cmInteCoLonInfo.setBizClassNo("3284");
        //16 BIZ_CLASS_NO 业务分类名称
        cmInteCoLonInfo.setBizClassName("个人消费业务");
        //17 PRODUCT_NO 产品编号
        cmInteCoLonInfo.setProductNo("CF21");
        //18 PROD_NAME 产品名称
        cmInteCoLonInfo.setProdName("兴安花");
        //19 VALUE_DT 起息日期
        cmInteCoLonInfo.setValueDt(countMain.getInterestStartDate());
        //20 MATURE_DT 到期日期 最后一期还款日
        //当前系统日期如果大于最后一期还款日，则时间为当前系统日期年月，日期为10号
        Date etlExpiryDate = firstLimitInfo.getEtlExpiryDate();
        Date lastPaymentDate = countMain.getLastPaymentDate();
        //21 LON_DT 借款日期
        cmInteCoLonInfo.setLonDt(countMain.getInterestStartDate());

        List<CmCustomerLimitInfo> cusLimits = iCustomerLimitInfoService.getCmCustomerLimitInfos(customerId, tenantId, organizationId, xahSeriesLimitIds);
        // 实际上的最大的额度有期限
        Date maxExpireDate = cusLimits.stream().map(CmCustomerLimitInfo::getLimitExpiryDate).max(Date::compareTo).orElse(busiDate);
        //22 PAYOFF_DT 结清日期 W 正常结清 X 非正常结清
        if ("W".equals(firstLevel.getBlockCode()) || "X".equals(firstLevel.getBlockCode())) {
            cmInteCoLonInfo.setPayoffDt(firstLevel.getBlockCodeUpdateDate());
        } else if (maxExpireDate.compareTo(busiDate) <= 0) {
            // 尝试查询是不是结清了
            String productId = xahSeriesProducts.get(0);
            String settleDate = iCustomerLimitInfoService.calculateSettleDate(tenantId, customerId, productId, organizationId, busiDate);
            Date etlExpireDate = null;
            if (StringUtils.isNotBlank(settleDate)) {
                Date etlSettleDate = DateUtils.parseDate(settleDate);
                // 1.到期之前结清的到期日取额度到期日 额度有效期不需要修改
                if (maxExpireDate.compareTo(etlSettleDate) >= 0) {
                    etlSettleDate = maxExpireDate;
                } else {
                    // 2.到期后结清的且延期过的
                    // 不需要修改结清日期，结清日期在延期日期内的  额度有效期需要调整为统计时间
                    if (maxExpireDate.compareTo(etlExpiryDate) < 0 && etlExpiryDate.compareTo(etlSettleDate) > 0) {
                        etlExpireDate = busiDate;
                    }
                }

                cmInteCoLonInfo.setPayoffDt(etlSettleDate);
                buildUpdateLimitChangeLog(bean, tenantId, customerId, etlContractNumber, etlLimitId, etlSettleDate, etlExpireDate, null);
            }
        }
        //23 FIRST_REPAY_DT 首次还款日期
        cmInteCoLonInfo.setFirstRepayDt(countMain.getFirstPaymentDate());
        //24 LON_TOTAL_TERM 贷款总期数  = 到期年月 - 起息年月
        int tltalTenor = this.tenor(countMain.getInterestStartDate(), lastPaymentDate);
        cmInteCoLonInfo.setLonTotalTerm(StringUtils.toString(tltalTenor));
        //26 MAX_GRACE_PERIOD 最大宽限期
        cmInteCoLonInfo.setMaxGracePeriod(pro.getGraceDays() + "");

        if (null != amDelinquencyInfo) {
            //27 OVDUE_BEGIN_DT 首次逾期日期 未关闭延滞交易账户
            cmInteCoLonInfo.setOvdueBeginDt(amDelinquencyInfo.getDelqDate());
            //28 MAX_OVDUE_DAYS 当前逾期天数
            cmInteCoLonInfo.setMaxOvdueDays(amDelinquencyInfo.getDelqDays());
        }

        //29 LON_USAGE_CD 借款用途代码
        cmInteCoLonInfo.setLonUsageCd("A99");
        //30 LON_USAGE_NAME 借款用途名称
        cmInteCoLonInfo.setLonUsageName("其他");
        //31 REPAY_WAY_CD 还款方式代码 02 等额本息
        cmInteCoLonInfo.setRepayWayCd("02");
        //32 REPAY_WAY_NAME 还款方式名称
        cmInteCoLonInfo.setRepayWayName("等额本息");
        //33 DAY_INT_RATE 日利率 最大日利率
        cmInteCoLonInfo.setDayIntRate(actualDailyRate + "");
        //34 INT_RATE_TYPE_CD 利率类型代码 0-日利率
        cmInteCoLonInfo.setIntRateTypeCd("0");
        //35 PRIN_REPAY_FREQ_CD 本金还款频率代码 0-月
        cmInteCoLonInfo.setPrinRepayFreqCd("0");
        //36 INT_REPAY_FREQ_CD 利息还款频率代码 0-月
        cmInteCoLonInfo.setIntRepayFreqCd("0");
        //37 OVDUE_CNT 逾期次数 (按照客户账单统计，当期有逾期 + 1)
        cmInteCoLonInfo.setOvdueCnt(BigDecimal.valueOf(overNum));
        //40 GUAR_WAY_CD 担保方式代码
        cmInteCoLonInfo.setGuarWayCd("400");

        // 扩展字段
        String extFields = mainInfo.getExtFields();
        if (StringUtils.isNotBlank(extFields)) {
            JSONObject jsonObject = JSONObject.parseObject(extFields);
            Object recverBankAcctNo = jsonObject.get("RECVER_BANK_ACCT_NO");
            Object recverAcctBank = jsonObject.get("RECVER_ACCT_BANK");
            Object recverName = jsonObject.get("RECVER_NAME");
            Object recverBankBankNo = jsonObject.get("RECVER_BANK_BANK_NO");
            Object recverBankFullname = jsonObject.get("RECVER_BANK_FULLNAME");
            //41 RECVER_BANK_ACCT_NO 收款人银行账号
            cmInteCoLonInfo.setRecverBankAcctNo(getString(recverBankAcctNo));
            //42 RECVER_ACCT_BANK 收款人账户银行
            cmInteCoLonInfo.setRecverAcctBank(getString(recverAcctBank));
            //43 RECVER_NAME 收款人名称
            cmInteCoLonInfo.setRecverName(getString(recverName));
            //66 RECVER_BANK_BANK_NO 收款人银行行号
            cmInteCoLonInfo.setRecverBankBankNo(getString(recverBankBankNo));
            //67 RECVER_BANK_FULLNAME 收款人银行全称
            cmInteCoLonInfo.setRecverBankFullname(getString(recverBankFullname));
        }

        //44 REPAY_ACCT_NO 还款账号
        cmInteCoLonInfo.setRepayAcctNo(Objects.nonNull(bank) && StringUtils.isNotBlank(bank.getCardNumber()) ? bank.getCardNumber() : "");

        //45 CUST_MGR_NO 客户经理编号
        cmInteCoLonInfo.setCustMgrNo(secondLevel.getBankMgrNo());
        //46 CUST_MGR_NAME 客户经理名称
        //47 BELONG_ORG_NO 所属机构编号
        cmInteCoLonInfo.setBelongOrgNo(secondLevel.getBankOrgNo());
        //48 BELONG_ORG_NAME 所属机构名称
        //49 ASSES_ORG_NO 考核机构编号
        cmInteCoLonInfo.setAssesOrgNo(secondLevel.getBankOrgNo());
        //50 ASSES_ORG_NAME 考核机构名称
        //51 SRC_PLAT_NO 来源平台编号
        cmInteCoLonInfo.setSrcPlatNo("CCS");
        //52 CURR_CD 币种代码
        cmInteCoLonInfo.setCurrCd("CNY");

        String accountStatus = "1";//贷款状态代码 0
        if (Objects.nonNull(cmInteCoLonInfo.getPayoffDt())) {
            //39 LON_STATUS_CD 贷款状态代码 1-正常 2-逾期 7-核销 8-正常结清 核销 > 逾期 > 正常
            accountStatus = "8";
        } else if (null != amDelinquencyInfo) {
            accountStatus = "2";//逾期
        }

        List<String> status = Arrays.asList(ReportingConstant.ACCOUNT_STATUS_0, ReportingConstant.ACCOUNT_STATUS_1, ReportingConstant.ACCOUNT_STATUS_2);
        // 获取客户贷款账户表 计算相关金额
        List<AmLoanAccountInfo> amLoanAccountInfoList = extAmLoanAccountInfoMapper.selectByCustProductsAndChannelAndStatus(customerId, channel, tenantId,
                status, xahSeriesProducts);
        BigDecimal ofbsOweIntBal = BigDecimal.ZERO;//表外欠息余额
        BigDecimal principal;//正常本金 所有已抛未还本金 （不包含逾期本金）
        BigDecimal ovdrPrincipal; //逾期本金
        String ovdueFlg = "0";//0 正常
        if (CollectionUtils.isNotEmpty(amLoanAccountInfoList)) {
            for (AmLoanAccountInfo acc : amLoanAccountInfoList) {
                // 1-非应计
                if (StringUtils.equals(acc.getNonAccrualsFlag(), TransBizConstant.NON_ACCRUALS_FLA_1)) {
                    ofbsOweIntBal = ofbsOweIntBal.add(acc.getInterestBalance()).add(acc.getPenaltyBalance()).add(acc.getCompoundBalance());
                }
            }
        }
        // 获取正常本金和逾期本金
        List<AmLoanAccountInfo> accountInfos = extAmLoanAccountInfoMapper.selectLoanAcctPrinBalWithProducts(customerId, channel, tenantId,
                null, xahSeriesProducts, busiDate);
        principal = accountInfos.stream()
                // payoffDate 是空的直接统计，不是空的统计结清日期为today的数据
                .filter(a -> Objects.isNull(a.getPayoffDate()) || (Objects.nonNull(a.getPayoffDate()) && a.getPayoffDate().compareTo(busiDate) > 0))
                .map(AmLoanAccountInfo::getNormalPrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        ovdrPrincipal = accountInfos.stream()
                .filter(a -> Objects.isNull(a.getPayoffDate()) || (Objects.nonNull(a.getPayoffDate()) && a.getPayoffDate().compareTo(busiDate) > 0))
                .map(AmLoanAccountInfo::getOvduePrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 统计不是today的且余额非0的数据
        List<String> loanIds = accountInfos.stream()
                // 结清的数据
                .filter(a -> Objects.nonNull(a.getPayoffDate())
                        // 往期结清的-实际上时间不能是上一天的23:00-24:00
                        && a.getPayoffDate().compareTo(busiDate) <= 0)
                .map(AmLoanAccountInfo::getLoanId).collect(Collectors.toList());
        cmInteCoLonInfo.setLoanIds(loanIds);
        logger.info("需要修改余额为0的借据编号：{}", JSONObject.toJSONString(loanIds));
        // 逾期金额大于0
        if (ovdrPrincipal.compareTo(BigDecimal.ZERO) > 0) {
            ovdueFlg = "1";//逾期
        }

        /*// 获取在贷中最大的《最后还款日期》
        AmLoanMainInfo max = extAmLoanMainInfoMapper.getLoaningLastPaymentDate(tenantId, customerId, status, xahSeriesProducts);
        Date matureDt = paymentDate;
        if (Objects.nonNull(max)) {
            matureDt = max.getLastPaymentDate();
        }
        // 0 正常 1 逾期
        if ("1".equalsIgnoreCase(ovdueFlg)) {
            cmInteCoLonInfo.setMatureDt(matureDt);
        } else {
            // 未逾期
            Calendar cal = Calendar.getInstance();
            cal.setTime(busiDate);
            Date nextPaymentDate = paymentDate;
            // 大于10号取下个月10号
            if (10 < cal.get(Calendar.DATE)) {
                nextPaymentDate = DateUtils.getDateByMonth(paymentDate, 1);
            }
            cmInteCoLonInfo.setMatureDt(nextPaymentDate.after(matureDt) ? nextPaymentDate : matureDt);
        }*/
        cmInteCoLonInfo.setMatureDt(lastPaymentDate);
        if (busiDate.after(lastPaymentDate)) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(busiDate);
            //系统日期和最后一期还款日月份相同
            Integer monthNum = DateUtils.calcGapMonths(lastPaymentDate, busiDate);
            if (monthNum >= 0) {
                //时间为系统日期的下一个月10号
                cal.add(Calendar.MONTH, 1);
            }
            //时间为当前系统日期年月，日期为10号
            int year = cal.get(Calendar.YEAR);
            int month = cal.get(Calendar.MONTH);
            cal.set(year, month, 10);
            Date nextPaymentDate = cal.getTime();
            if (nextPaymentDate.after(etlExpiryDate)) {
                // 到期日期必须小于等于（客户最后还款日期与额度有效期两者的最大值）
                cmInteCoLonInfo.setMatureDt(etlExpiryDate.after(lastPaymentDate) ? etlExpiryDate : lastPaymentDate);
            } else {
                cmInteCoLonInfo.setMatureDt(nextPaymentDate);
            }
        }

        // 逾期相同年月份需要去重
        Set<String> delayMonths = new HashSet<>();
        List<AmAccountMainInfo> amAccountMainInfoList = extAmAccountMainInfoMapper.selectByStatusProductsAndType(null, new String[]{TransBizConstant.ACCOUNT_STATUS_2},
                new String[]{TransBizConstant.ACCOUNT_TYPE_06,TransBizConstant.ACCOUNT_TYPE_11}, null, customerId, tenantId, xahSeriesProducts);
        Date nextProcessingDate = org.getNextProcessingDate();

        amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .forEach(d -> {
            String monthDay = DateUtils.format(d.getPaymentDueDate(), "yyyyMM");
            delayMonths.add(monthDay);
        });
        // 逾期的总期数(去重年月) - 逾期：有本金逾期，按照本金的期数来计算；没有本金，按照1期来计算
        cmInteCoLonInfo.setOvdueTermCnt(delayMonths.size() == 0 && amAccountMainInfoList.size() > 0 ? BigDecimal.ONE : new BigDecimal(delayMonths.size()));
        // 逾期1-30天未归还本金
        BigDecimal delayDay1 = amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .filter(d -> DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) >= 1 && DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) <= 30)
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 逾期31-60天未归还本金
        BigDecimal delayDay2 = amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .filter(d -> DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) >= 31 && DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) <= 60)
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 逾期61-90天未归还本金
        BigDecimal delayDay3 = amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .filter(d -> DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) >= 61 && DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) <= 90)
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 逾期91-180天未归还本金
        BigDecimal delayDay4 = amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .filter(d -> DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) >= 91 && DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) <= 180)
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 逾期180天以上未归还本金
        BigDecimal delayDay5 = amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .filter(d -> DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) >= 181)
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        cmInteCoLonInfo.setDelayDay1(delayDay1);
        cmInteCoLonInfo.setDelayDay2(delayDay2);
        cmInteCoLonInfo.setDelayDay3(delayDay3);
        cmInteCoLonInfo.setDelayDay4(delayDay4);
        cmInteCoLonInfo.setDelayDay5(delayDay5);
        //38 OVDUE_FLG 逾期标志 4级分类 0 正常 1 逾期
        cmInteCoLonInfo.setOvdueFlg(ovdueFlg);
        //39 LON_STATUS_CD 贷款状态代码 1-正常 2-逾期 7-核销 8-正常结清 核销 > 逾期 > 正常
        cmInteCoLonInfo.setLonStatusCd(accountStatus);
        //53 NORMAL_PRIN_BAL 正常本金余额
        cmInteCoLonInfo.setNormalPrinBal(principal);
        //54 OVDUE_PRIN_BAL 逾期本金余额
        cmInteCoLonInfo.setOvduePrinBal(ovdrPrincipal);
        // 计算息费
        this.calculateInter(cmInteCoLonInfo, tenantId, customerId, xahSeriesProducts);
        //57 HANG_INT_BAL 挂息金额
        cmInteCoLonInfo.setHangIntBal(BigDecimal.ZERO);
        //58 PUNISH_INT_INT_RATE 罚息利率
        cmInteCoLonInfo.setPunishIntIntRate(penaltyRate + "");
        //59 LON_AMT 借款金额
//        AmLoanMainInfo currMain = extAmLoanMainInfoMapper.countLoanAmount(firstLevel.getCustomerId(), firstLevel.getTenantId());
        // 根据客户id查询用户贷款总金额
        List<String> xahCreditProducts = BizTypeProducts.getXAHCreditProducts();
        BigDecimal loanAmount = extAmLoanMainInfoMapper.sumAmountByCustomerIdProducts(customerId, tenantId, xahCreditProducts, etlEffectiveDate);
        if (cancelFist) {
            // 只有首笔且取消的情况
            loanAmount = countMain.getLoanAmount();
        }
        cmInteCoLonInfo.setLonAmt(loanAmount);
        //60 CURR_BAL 当期余额
        // 根据用户id 查询剩余本金--所有未还本金（包含未抛部分）
        //BigDecimal currBal = extAmLoanAccountInfoMapper.sumCurrBalByCustomerIdProducts(firstLevel.getCustomerId(), firstLevel.getTenantId(),
        //        Arrays.asList(TransBizConstant.ACCOUNT_STATUS_0, TransBizConstant.ACCOUNT_STATUS_1, TransBizConstant.ACCOUNT_STATUS_2), xahSeriesProducts);
        //cmInteCoLonInfo.setCurrBal(currBal);
        cmInteCoLonInfo.setCurrBal(cmInteCoLonInfo.getNormalPrinBal().add(cmInteCoLonInfo.getOvduePrinBal()));
        //61 CLCURR_CURR_BAL 折本币当期余额
        cmInteCoLonInfo.setClcurrCurrBal(cmInteCoLonInfo.getCurrBal());
        //62 YEAR_INT_RATE 年利率
        cmInteCoLonInfo.setYearIntRate(countMain.getInterestRate() + "");
        //63 LON_DIR_CD 贷款投向行业代码
        //64 ORG_CONTRI_RATIO 机构出资比例
        //65 LON_TYPE_CD 贷款类型代码 消费贷-0200 经营贷-0300
        if (pro.getTableType().equals(ReportingConstant.LOAN_TYPE_6)) {
            cmInteCoLonInfo.setLonTypeCd("0300");
        } else {
            cmInteCoLonInfo.setLonTypeCd("0200");
        }
        //69 OFBS_OWE_INT_BAL 表外欠息余额
        cmInteCoLonInfo.setOfbsOweIntBal(ofbsOweIntBal);
        // 70 NTXE_REPAY_DT 下次还款日期
        //获取下期还款日 10号以前当月 10号以后下个月
        int curDD = Integer.parseInt(DateUtils.formatDate(busiDate).substring(9, 10));
        if (curDD >= 10) {
            paymentDate = DateUtils.getDateByMonth(paymentDate, 1);
        }
        cmInteCoLonInfo.setNtxeRepayDt(paymentDate);
        cmInteCoLonInfo.setTenantId(tenantId);
        /**
         * 25 PAID_TERM 已还期数
         * 除每月10日和13日外，其他日期每日取上一日的该值。
         * 每月10日和13日的批次，进行以下判断：
         * 本期账单金额大于0，且当前逾期状态为正常。
         * 若符合条件，则取上月10日和13日的已还期数+1。
         * 若不符合条件，则取上一日的已还期数。(改成上一次)
         */
        int currDD = Integer.parseInt(DateUtils.getDay(busiDate));
        CmInteCoLonInfo historyInfo = extCmInteCoLonInfoMapper.findLastWithLimitIds(secondLevel.getCustomerId(), secondLevel.getTenantId(), xahSeriesLimitIds, etlEffectiveDate);
        int paidTerm = 0;
        Date thisMonthDate = DateUtils.getThisMonthDate(busiDate, 10);
        BigDecimal currBillBal = extAmRepaymentPlanInfoMapper.plansByCustomerIdProducts(customerId, tenantId, thisMonthDate, xahSeriesProducts);
        if (Objects.nonNull(historyInfo) && (currDD == 10 || currDD == 13) && "1".equals(cmInteCoLonInfo.getLonStatusCd()) && BigDecimal.ZERO.compareTo(currBillBal) < 0) {
            if (currDD == 10) {
                paidTerm = Integer.parseInt(historyInfo.getPaidTerm()) + 1;
            } else if (currDD == 13) {
                // 如果9号的数据为空
                CmInteCoLonInfo newHistoryInfo = extCmInteCoLonInfoMapper.findByCustomerIdAndEtlDtWithLimitIds(secondLevel.getCustomerId(), DateUtils.getThisMonthDate(busiDate, 9), secondLevel.getTenantId(),
                        xahSeriesLimitIds);
                // 跟9号历史数据一样
                if (!Objects.isNull(newHistoryInfo) && newHistoryInfo.getPaidTerm().equals(historyInfo.getPaidTerm())) {
                    paidTerm = Integer.parseInt(newHistoryInfo.getPaidTerm()) + 1;
                } else {
                    paidTerm = Integer.parseInt(historyInfo.getPaidTerm());
                }
            }
        } else if (Objects.nonNull(historyInfo)) {
            paidTerm = Integer.parseInt(historyInfo.getPaidTerm());
        }
        if (cancelFist) {
            paidTerm = 1;
        }
        cmInteCoLonInfo.setPaidTerm(paidTerm + "");


        BigDecimal maxDebt = BigDecimal.ZERO;
        maxDebt = maxDebt.add(principal).add(ovdrPrincipal);
        String currentYearFirst = DateUtils.format(DateUtils.getCurrentYearFirst(busiDate));
        String currentYear = currentYearFirst.substring(0, 4);
        List<CmInteCoLonInfo> lonInfos = extCmInteCoLonInfoMapper.queryLonInfos(currentYear, customerId, tenantId);

        // 当年累计余额
        BigDecimal yearNormalPrinBal = lonInfos.stream().map(CmInteCoLonInfo::getNormalPrinBal).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal yearOvduePrinBal = lonInfos.stream().map(CmInteCoLonInfo::getOvduePrinBal).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal yearAccrualBal = yearNormalPrinBal.add(yearOvduePrinBal).add(maxDebt);
        cmInteCoLonInfo.setYearAccumBal(yearAccrualBal);
        // 当年平均余额
        int dayOfYear = DateUtils.getDayOfYear(busiDate);
        cmInteCoLonInfo.setyAvgBal(yearAccrualBal.divide(new BigDecimal(dayOfYear), CommonContants.BIGDECIMAL_SCALE, BigDecimal.ROUND_HALF_UP));
        // 当季累计余额
        Date quarterFirstDate = DateUtils.getQuarterFirstDate(busiDate);
        BigDecimal quarterNormalPrinBal = lonInfos.stream()
                .filter(lon -> lon.getEtlDt().compareTo(quarterFirstDate) >= 0)
                .map(CmInteCoLonInfo::getNormalPrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal quarterOvduePrinBal = lonInfos.stream()
                .filter(lon -> lon.getEtlDt().compareTo(quarterFirstDate) >= 0)
                .map(CmInteCoLonInfo::getOvduePrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal seasonalAccrualBal = quarterNormalPrinBal.add(quarterOvduePrinBal).add(maxDebt);
        cmInteCoLonInfo.setQuarAccumBal(seasonalAccrualBal);
        int seasonDays = DateUtils.getDiffDays(quarterFirstDate, busiDate) + 1;
        // 当季平均余额
        cmInteCoLonInfo.setqAvgBal(seasonalAccrualBal.divide(new BigDecimal(seasonDays), CommonContants.BIGDECIMAL_SCALE, BigDecimal.ROUND_HALF_UP));
        // 当月累计余额
        Date monthFirstDate = DateUtils.getMonthStartTime(busiDate);
        BigDecimal monthNormalPrinBal = lonInfos.stream()
                .filter(lon -> lon.getEtlDt().compareTo(monthFirstDate) >= 0)
                .map(CmInteCoLonInfo::getNormalPrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal monthOvduePrinBal = lonInfos.stream()
                .filter(lon -> lon.getEtlDt().compareTo(monthFirstDate) >= 0)
                .map(CmInteCoLonInfo::getOvduePrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal monthAccrualBal = monthNormalPrinBal.add(monthOvduePrinBal).add(maxDebt);
        cmInteCoLonInfo.setMonAccumBal(monthAccrualBal);
        int dayOfMonth = DateUtils.getDayOfMonth(busiDate);
        // 当月平均余额
        cmInteCoLonInfo.setmAvgBal(monthAccrualBal.divide(new BigDecimal(dayOfMonth), CommonContants.BIGDECIMAL_SCALE, BigDecimal.ROUND_HALF_UP));

        //获取上一日的贷款信息
        Date yesterday = DateUtils.addDay(busiDate, -1);
        //73 MAX_DEBT 最大负债额
        BigDecimal lastMaxDebt = lonInfos.stream()
                .filter(lon -> DateUtils.format(lon.getEtlDt()).equalsIgnoreCase(DateUtils.format(yesterday)))
                .filter(lon -> lon.getDubilNo().equalsIgnoreCase(loanId))
                .sorted(Comparator.comparing(CmInteCoLonInfo::getEtlDt))
                .map(CmInteCoLonInfo::getMaxDebt)
                .findFirst().orElse(BigDecimal.ZERO);
        if (maxDebt.compareTo(lastMaxDebt) < 0) {
            maxDebt = lastMaxDebt;
        }
        cmInteCoLonInfo.setMaxDebt(maxDebt);

        // 根据交易日期（业务日期）分组查询贷款信息
        List<AmLoanMainInfoVo> list = extAmLoanMainInfoMapper.selectLoanInfoWithProductsGroupByDay(tenantId, customerId, xahSeriesProducts);
        // 当日提款笔数
        cmInteCoLonInfo.setTodayDrawCnt(0);
        // 当日提款金额
        cmInteCoLonInfo.setTodayDrawAmt(BigDecimal.ZERO);
        // 累计提款笔数
        cmInteCoLonInfo.setAccumDrawCnt(0);
        if (CollectionUtils.isNotEmpty(list)) {
            AmLoanMainInfoVo amLoanMainInfoVo = list.stream().filter(a -> a.getPostingDate().equals(busiDate)).findAny().orElse(null);
            if (!Objects.isNull(amLoanMainInfoVo)) {
                // 当日提款笔数
                cmInteCoLonInfo.setTodayDrawCnt(amLoanMainInfoVo.getLoanCount());
                // 当日提款金额
                cmInteCoLonInfo.setTodayDrawAmt(amLoanMainInfoVo.getSumAmount());
            }
            Integer totalLoan = list.stream().filter(a -> a.getPostingDate().compareTo(etlEffectiveDate) > 0).map(AmLoanMainInfoVo::getLoanCount).reduce(0, Integer::sum);
            // 累计提款笔数
            cmInteCoLonInfo.setAccumDrawCnt(totalLoan);
        }
        bean.setCmInteCoLonInfo(cmInteCoLonInfo);
        return bean;
    }

    /**
     * 计算息费
     * @param cmInteCoLonInfo
     * @param tenantId
     * @param customerId
     * @param products
     */
    private void calculateInter(CmInteCoLonInfo cmInteCoLonInfo, String tenantId, String customerId, List<String> products) {
        List<AmAccountMainInfo> amAccountMainInfoList = extAmAccountMainInfoMapper.selectAccountsByproductIds(tenantId, customerId, null,
                Arrays.asList(TransBizConstant.ACCOUNT_TYPE_04, TransBizConstant.ACCOUNT_TYPE_11),
                Collections.singletonList(TransBizConstant.ACCOUNT_STATUS_2), products);
        List<AmInterestAccrualInfo> amInterestAccrualInfoList = extAmInterestAccrualInfoMapper.selectByCustWithProducts(customerId, tenantId,
                Collections.singletonList(TransBizConstant.ACCOUNT_STATUS_1), products);
        BigDecimal punishInterOne = amAccountMainInfoList.stream()
                .filter(acct -> TransBizConstant.ACCOUNT_TYPE_11.equalsIgnoreCase(acct.getAccountType()))
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal normalInter = amAccountMainInfoList.stream()
                .filter(acct -> TransBizConstant.ACCOUNT_TYPE_04.equalsIgnoreCase(acct.getAccountType()))
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal lgInter = amInterestAccrualInfoList.stream()
                .filter(acct -> TransBizConstant.INTEREST_ACCRUAL_TYPE_66.equalsIgnoreCase(acct.getAccountType()))
                .map(AmInterestAccrualInfo::getAccrualTotalAccruInterest).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal punishInterTwo = amInterestAccrualInfoList.stream()
                .filter(acct -> TransBizConstant.INTEREST_ACCRUAL_TYPE_10.equalsIgnoreCase(acct.getAccountType()))
                .map(AmInterestAccrualInfo::getAccrualTotalAccruInterest).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal punishInter = punishInterOne.add(punishInterTwo);
        //55 PUNISH_INT_AMT 罚息金额（当期应还罚息）
        cmInteCoLonInfo.setPunishIntAmt(punishInter);
        if (punishInter.compareTo(BigDecimal.ZERO) <= 0) {
            // 没有存在逾期的情况
            lgInter = lgInter.add(normalInter);
            normalInter = BigDecimal.ZERO;
        }
        //56 OWE_INT_AMT 欠息金额(逾期：值=每一期未归还的利息总和；未逾期：0)
        cmInteCoLonInfo.setOweIntAmt(normalInter);
        //68 CURR_PROVIED_INT 当期已计提利息（当期应还利息）
        cmInteCoLonInfo.setCurrProviedInt(lgInter);
    }

    @Override
    public CmInteCoLonInfoBean assemLoanInfoXaj(CmInteCoLonInfo loanInfo) throws TxnException {
        CmInteCoLonInfoBean bean = new CmInteCoLonInfoBean();
        //如果为空直接返回
        if (null == loanInfo) {
            return null;
        }
        String dubilNo = loanInfo.getDubilNo();
        String tenantId = loanInfo.getTenantId();
        String customerId = loanInfo.getCustNo();
        PrOrganizationTable org = organizationTableService.findByOrId(TransBizConstant.DEFAULT_ORG_ID, tenantId);
        PrCreditLimitMapping prCreditLimitMapping = extPrCreditLimitMappingMapper.selectByTenIdAndProIdAndChannel(tenantId, TransBizConstant.DEFAULT_CHANNEL_NO, BizTypeProducts.XAJ_PRODUCT);
        if (null == prCreditLimitMapping) {
            String message = MessageFormat.format("根据tenantId:{0},channel:{1},productId:{2},未找到对应的limitMapping", tenantId, TransBizConstant.DEFAULT_CHANNEL_NO, BizTypeProducts.XAJ_PRODUCT);
            throw new TxnBizException(TxnRespCode.NO_DATA.getCode(), message);
        }
        //兴安借不会有多个
        CmCustomerLimitInfo limitInfo = extCmCustomerLimitInfoMapper.selectByTenIdAndCusIdAndLimitId(tenantId, customerId, prCreditLimitMapping.getLimitId());
        if (limitInfo == null || "".equals(limitInfo.getSeqNo())){
            return null;
        }

        //兴安借系列产品
        List<String> xajSeriesProducts = BizTypeProducts.getXAJSeriesProducts();

        //获取客户相关的所有额度编号，做集合运算  兴安借系列产品对应的额度列表
        List<String> xajSeriesLimitIds = extPrCreditLimitMappingMapper.selectLimitIdByTenIdAndProductIds(tenantId, xajSeriesProducts);
        if (xajSeriesLimitIds.isEmpty()) {
            logger.warn("assemLoanInfo|没有找到产品列表xajSeriesProducts：{}对应的LimitId", JSON.toJSONString(xajSeriesProducts));
            return null;
        }

        // 获取用户"首笔贷款额度信息"
        CmLimitChangeLog firstLimitInfo = iCustomerLimitInfoService.queryFirstLimitChangeLog(tenantId, customerId, xajSeriesProducts);
        if (null == firstLimitInfo) {
            logger.info("没有查询到首次额度生效日期，客户id:{},机构id:{}", tenantId, customerId);
            return null;
        }
        Date eltSettleDate = firstLimitInfo.getEtlSettleDate();
        Date busiDate = org.getToday();
        if (Objects.nonNull(eltSettleDate) && busiDate.compareTo(eltSettleDate) > 0) {
            logger.info("已经结清不需要再供数，客户id:{}", customerId);
            return null;
        }
        String etlContractNumber = firstLimitInfo.getEtlContractNumber();
        String etlLimitId = firstLimitInfo.getEtlLimitId();
        /// 订单信息
        AmLoanAccountInfo countAcct = extAmLoanAccountInfoMapper.selectByLoanIdForBatch(dubilNo);
        if (null == countAcct) {
            return null;
        }
        //统计客户订单查询
        Date etlEffectiveDate = firstLimitInfo.getEtlEffectiveDate();
        Date payoffDt = loanInfo.getPayoffDt();
        Date today = org.getToday();
        if (Objects.nonNull(payoffDt) && today.compareTo(payoffDt) > 0) {
            logger.info("已经结清不需要再供数，客户id:{}", customerId);
            return null;
        }

        String channel = countAcct.getChannel();
        String organizationId = countAcct.getOrganizationId();

        CmInteCoLonInfo cmInteCoLonInfo = new CmInteCoLonInfo();
        BeanUtils.copyProperties(loanInfo, cmInteCoLonInfo);
        //1 ETL_DT 数据日期
        cmInteCoLonInfo.setEtlDt(busiDate);
        //2 LP_ORG_NO 法人机构标识
        cmInteCoLonInfo.setLpOrgNo("XIB");
        // 设置首笔借据
        if (StringUtils.isBlank(firstLimitInfo.getEtlLoanId())) {
            buildUpdateLimitChangeLog(bean, tenantId, customerId, etlContractNumber, etlLimitId, null, null, dubilNo);
        }
        //8 CRDT_CONT_NO 授信合同编号
        cmInteCoLonInfo.setCrdtContNo(etlContractNumber);
        //9 LMT_NO 额度编号
        cmInteCoLonInfo.setLmtNo(etlLimitId);
        //10 SUBJECT_NO 科目编号
        cmInteCoLonInfo.setSubjectNo("11400301");
        //11 LEVEL5_CLASS_CD 五级分类代码
        //12 LEVEL5_CLASS_NAME 五级分类名称
        //13 LEVEL10_CLASS_CD 十级分类代码
        //14 LEVEL10_CLASS_NAME 十级分类名称
        //15 BIZ_CLASS_NO 业务分类编号
        cmInteCoLonInfo.setBizClassNo("3284");
        //16 BIZ_CLASS_NO 业务分类名称
        cmInteCoLonInfo.setBizClassName("个人消费业务");
        //17 PRODUCT_NO 产品编号
        cmInteCoLonInfo.setProductNo("CF23");
        //18 PROD_NAME 产品名称
        cmInteCoLonInfo.setProdName("兴安借");
        //20 MATURE_DT 到期日期 最后一期还款日
        //当前系统日期如果大于最后一期还款日，则时间为当前系统日期年月，日期为10号
        Date etlExpiryDate = firstLimitInfo.getEtlExpiryDate();
        //借据信息
        AmLoanMainInfo mainInfo = extAmLoanMainInfoMapper.selectByLoanIdAndCusId(dubilNo, customerId, tenantId);
        //还款计划 查询最后一期还款日
        AmRepaymentPlanInfo plan = extAmRepaymentPlanInfoMapper.queryMaxPaymentDueDate(dubilNo,customerId,tenantId);
        if (plan!= null && plan.getPaymentDueDate()!=null){
            //贷款到期日 取最后一期还款日
            cmInteCoLonInfo.setMatureDt(plan.getPaymentDueDate());
        }
        // 实际上的最大的额度有期限
        Date maxExpireDate = limitInfo.getLimitExpiryDate();
        // 尝试查询是不是结清了
        String settleDate = iCustomerLimitInfoService.calculateSettleDate(tenantId, customerId, mainInfo.getProductId(), organizationId, busiDate);
        Date etlExpireDate = null;
        if (StringUtils.isNotBlank(settleDate)) {
            Date etlSettleDate = DateUtils.parseDate(settleDate);
            // 1.到期之前结清的到期日取额度到期日 额度有效期不需要修改
            if (maxExpireDate.compareTo(etlSettleDate) >= 0) {
                etlSettleDate = maxExpireDate;
            } else {
                // 2.到期后结清的且延期过的
                // 不需要修改结清日期，结清日期在延期日期内的  额度有效期需要调整为统计时间
                if (maxExpireDate.compareTo(etlExpiryDate) < 0 && etlExpiryDate.compareTo(etlSettleDate) > 0) {
                    etlExpireDate = busiDate;
                }
            }
            cmInteCoLonInfo.setPayoffDt(etlSettleDate);
            buildUpdateLimitChangeLog(bean, tenantId, customerId, etlContractNumber, etlLimitId, etlSettleDate, etlExpireDate, null);
        }
        //获取产品信息
        PrProductTable pro = productTableService.findProByProIdAndOrgId(mainInfo.getProductId(), organizationId, tenantId);
        //26 MAX_GRACE_PERIOD 最大宽限期
        cmInteCoLonInfo.setMaxGracePeriod(pro.getGraceDays() + "");

        //获取当期还款日
        Date paymentDate = getCurrPaymentDate(busiDate);

        //查询罚息累计账户
        BigDecimal lgPenInter = BigDecimal.ZERO;//累计罚息
        BigDecimal lgInter = BigDecimal.ZERO;//计提利息
        // 根据借据编号查询客户下所有正常计提的累计账户
        List<AmInterestAccrualInfo> amInterestAccrualInfoList = extAmInterestAccrualInfoMapper.selectAllAccuAcct(loanInfo.getDubilNo(), loanInfo.getCustNo(), loanInfo.getTenantId(),
                null, Arrays.asList(TransBizConstant.ACCOUNT_STATUS_1));
        if (CollectionUtils.isNotEmpty(amInterestAccrualInfoList)) {
            for (AmInterestAccrualInfo interestAccrualInfo : amInterestAccrualInfoList) {
                if (TransBizConstant.INTEREST_ACCRUAL_TYPE_10.equals(interestAccrualInfo.getAccountType())) {
                    lgPenInter = lgPenInter.add(interestAccrualInfo.getAccrualTotalAccruInterest());
                }
                if (TransBizConstant.INTEREST_ACCRUAL_TYPE_66.equals(interestAccrualInfo.getAccountType())) {
                    // 每个月9号需要特殊处理，ACCOUNT_STATUS会变成8-已完成计息
                    if (DateUtils.addDay(paymentDate, -1).equals(busiDate)) {
                        List<AmInterestAccrualInfo> list = extAmInterestAccrualInfoMapper.selectAllAccuAcct(loanInfo.getDubilNo(), loanInfo.getCustNo(), loanInfo.getTenantId(),
                                null, Arrays.asList(TransBizConstant.ACCOUNT_STATUS_8));
                        if (CollectionUtils.isNotEmpty(list)) {
                            for (AmInterestAccrualInfo a : list) {
                                lgInter = lgInter.add(a.getAccrualTotalAccruInterest());
                            }
                        }
                    } else {
                        lgInter = lgInter.add(interestAccrualInfo.getAccrualTotalAccruInterest());
                    }
                }
            }
        }

        // 根据借据编号获取最大日利率
        AmLoanMainInfo countMain2 = extAmLoanMainInfoMapper.getMaxDailyRateByLoanId(dubilNo, customerId, tenantId);
        // 日利率和罚息利率取值是正常和逾期的最大值，如果查询不到，则默认值为0
        BigDecimal actualDailyRate = BigDecimal.ZERO;
        if (null != countMain2 && null != countMain2.getActualDailyRate()) {
            actualDailyRate = countMain2.getActualDailyRate();
        }

        //查询罚息利率参数 获取客户最大罚息利率
        BigDecimal penaltyRate = BigDecimal.ZERO;
        if (StringUtils.isNotBlank(loanInfo.getPunishIntIntRate())) {
            PrPenaltyRateTable prPenaltyRateTable = prPenaltyRateTableService.findByPenaltyId(loanInfo.getPunishIntIntRate(), org.getOrganizationId(), tenantId);
            BigDecimal currTate = BigDecimal.ZERO;
            if (ReportingConstant.INCREASE_TYPE_0.equals(prPenaltyRateTable.getIncreaseType())) {
                currTate = prPenaltyRateTable.getIncreaseNum();
            } else if (ReportingConstant.INCREASE_TYPE_1.equals(prPenaltyRateTable.getIncreaseType())) {
                currTate = actualDailyRate.multiply(new BigDecimal(1).add(prPenaltyRateTable.getIncreaseNum()));
            }
            if (penaltyRate.compareTo(currTate) < 0) {
                penaltyRate = currTate;
            }
        }

        //查询客户逾期信息
        AmDelinquencyInfo amDelinquencyInfo = extAmDelinquencyInfoMapper.getByLoanIdMaxDelqDaysInfoWithProducts(customerId, tenantId, dubilNo,ReportingConstant.ACCOUNT_STATUS_1, xajSeriesProducts);
        if (null != amDelinquencyInfo) {
            //27 OVDUE_BEGIN_DT 首次逾期日期 未关闭延滞交易账户
            cmInteCoLonInfo.setOvdueBeginDt(amDelinquencyInfo.getDelqDate());
            //28 MAX_OVDUE_DAYS 当前逾期天数
            cmInteCoLonInfo.setMaxOvdueDays(amDelinquencyInfo.getDelqDays());
        }

        //29 LON_USAGE_CD 借款用途代码
        cmInteCoLonInfo.setLonUsageCd(getLoanUseCd(mainInfo.getLoanUse()));
        //30 LON_USAGE_NAME 借款用途名称
        cmInteCoLonInfo.setLonUsageName(getLonUsageName(mainInfo.getLoanUse()));
        //31 REPAY_WAY_CD 还款方式代码
        cmInteCoLonInfo.setRepayWayCd(getRepayWayCd(mainInfo.getAmortMethodTableId()));
        //32 REPAY_WAY_NAME 还款方式名称
        cmInteCoLonInfo.setRepayWayName(getRepayWayName(mainInfo.getAmortMethodTableId()));
        //33 DAY_INT_RATE 日利率 最大日利率
        cmInteCoLonInfo.setDayIntRate(actualDailyRate + "");

        //34 INT_RATE_TYPE_CD 利率类型代码 0-日利率
        cmInteCoLonInfo.setIntRateTypeCd("0");
        //35 PRIN_REPAY_FREQ_CD 本金还款频率代码 0-月
        cmInteCoLonInfo.setPrinRepayFreqCd("0");
        //36 INT_REPAY_FREQ_CD 利息还款频率代码 0-月
        cmInteCoLonInfo.setIntRepayFreqCd("0");
        //40 GUAR_WAY_CD 担保方式代码
        cmInteCoLonInfo.setGuarWayCd("400");

        // 扩展字段
        String extFields = mainInfo.getExtFields();
        if (StringUtils.isNotBlank(extFields)) {
            JSONObject jsonObject = JSONObject.parseObject(extFields);
            Object recverBankAcctNo = jsonObject.get("RECVER_BANK_ACCT_NO");
            Object recverAcctBank = jsonObject.get("RECVER_ACCT_BANK");
            Object recverName = jsonObject.get("RECVER_NAME");
            Object recverBankBankNo = jsonObject.get("RECVER_BANK_BANK_NO");
            Object recverBankFullname = jsonObject.get("RECVER_BANK_FULLNAME");
            //41 RECVER_BANK_ACCT_NO 收款人银行账号
            cmInteCoLonInfo.setRecverBankAcctNo(getString(recverBankAcctNo));
            //42 RECVER_ACCT_BANK 收款人账户银行
            cmInteCoLonInfo.setRecverAcctBank(getString(recverAcctBank));
            //43 RECVER_NAME 收款人名称
            cmInteCoLonInfo.setRecverName(getString(recverName));
            //66 RECVER_BANK_BANK_NO 收款人银行行号
            cmInteCoLonInfo.setRecverBankBankNo(getString(recverBankBankNo));
            //67 RECVER_BANK_FULLNAME 收款人银行全称
            cmInteCoLonInfo.setRecverBankFullname(getString(recverBankFullname));
        }

        //获取客户二级信息
        CmCustomerSecondLevel secondLevel = customerService.getSecondByChannelAndCustomerIdAndTensnId(channel, customerId, tenantId, pro.getProductId());
        //获取当期还款日
        //45 CUST_MGR_NO 客户经理编号
        cmInteCoLonInfo.setCustMgrNo(secondLevel.getBankMgrNo());
        //46 CUST_MGR_NAME 客户经理名称
        //47 BELONG_ORG_NO 所属机构编号
        cmInteCoLonInfo.setBelongOrgNo(secondLevel.getBankOrgNo());
        //48 BELONG_ORG_NAME 所属机构名称
        //49 ASSES_ORG_NO 考核机构编号
        cmInteCoLonInfo.setAssesOrgNo(secondLevel.getBankOrgNo());
        //50 ASSES_ORG_NAME 考核机构名称

        //51 SRC_PLAT_NO 来源平台编号
        cmInteCoLonInfo.setSrcPlatNo("CCS");
        //52 CURR_CD 币种代码
        cmInteCoLonInfo.setCurrCd("CNY");

        // 获取客户贷款账户表 计算相关金额
        AmLoanAccountInfo amLoanAccountInfo = extAmLoanAccountInfoMapper.selectByLoanIdAndAccountStatus(dubilNo, customerId, tenantId,
                Arrays.asList(ReportingConstant.ACCOUNT_STATUS_0, ReportingConstant.ACCOUNT_STATUS_1, ReportingConstant.ACCOUNT_STATUS_2));
        BigDecimal ofbsOweIntBal = BigDecimal.ZERO;//表外欠息余额
        BigDecimal principal;//正常本金 所有已抛未还本金 （不包含逾期本金）
        BigDecimal ovdrPrincipal; //逾期本金
        String ovdueFlg = "0";//0 正常
        if (Objects.nonNull(amLoanAccountInfo)) {
            // 1-非应计
            if (StringUtils.equals(amLoanAccountInfo.getNonAccrualsFlag(), TransBizConstant.NON_ACCRUALS_FLA_1)) {
                ofbsOweIntBal = ofbsOweIntBal.add(amLoanAccountInfo.getInterestBalance()).add(amLoanAccountInfo.getPenaltyBalance()).add(amLoanAccountInfo.getCompoundBalance());
            }
        }
        // 获取正常本金和逾期本金   贷款订单维度
        List<AmLoanAccountInfo> accountInfos = extAmLoanAccountInfoMapper.selectLoanAcctPrinBal(customerId, channel, tenantId, dubilNo);
        principal = accountInfos.stream()
                // payoffDate 是空的直接统计，不是空的统计结清日期为today的数据
                .filter(a -> Objects.isNull(a.getPayoffDate()) || (Objects.nonNull(a.getPayoffDate()) && a.getPayoffDate().compareTo(busiDate) > 0))
                .map(AmLoanAccountInfo::getNormalPrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        ovdrPrincipal = accountInfos.stream()
                .filter(a -> Objects.isNull(a.getPayoffDate()) || (Objects.nonNull(a.getPayoffDate()) && a.getPayoffDate().compareTo(busiDate) > 0))
                .map(AmLoanAccountInfo::getOvduePrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 统计不是today的且余额非0的数据
        List<String> loanIds = accountInfos.stream()
                // 结清的数据
                .filter(a -> Objects.nonNull(a.getPayoffDate())
                        // 往期结清的-实际上时间不能是上一天的23:00-24:00
                        && a.getPayoffDate().compareTo(busiDate) <= 0)
                .map(AmLoanAccountInfo::getLoanId).collect(Collectors.toList());
        cmInteCoLonInfo.setLoanIds(loanIds);
        logger.info("需要修改余额为0的借据编号：{}", JSONObject.toJSONString(loanIds));
        // 逾期金额大于0
        if (ovdrPrincipal.compareTo(BigDecimal.ZERO) > 0) {
            ovdueFlg = "1";//逾期
        }
        // 逾期相同年月份需要去重
        Set<String> delayMonths = new HashSet<>();
        List<AmAccountMainInfo> amAccountMainInfoList = extAmAccountMainInfoMapper.selectByStatusProductsAndType(dubilNo, new String[]{TransBizConstant.ACCOUNT_STATUS_2},
                new String[]{TransBizConstant.ACCOUNT_TYPE_06,TransBizConstant.ACCOUNT_TYPE_11}, null, customerId, tenantId, xajSeriesProducts);
        Date nextProcessingDate = org.getNextProcessingDate();

        amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .forEach(d -> {
                    String monthDay = DateUtils.format(d.getPaymentDueDate(), "yyyyMM");
                    delayMonths.add(monthDay);
                });
        // 逾期的总期数(去重年月) - 逾期：有本金逾期，按照本金的期数来计算；没有本金，按照1期来计算
        cmInteCoLonInfo.setOvdueTermCnt(delayMonths.size() == 0 && amAccountMainInfoList.size() > 0 ? BigDecimal.ONE : new BigDecimal(delayMonths.size()));
        // 逾期1-30天未归还本金
        BigDecimal delayDay1 = amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .filter(d -> DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) >= 1 && DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) <= 30)
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 逾期31-60天未归还本金
        BigDecimal delayDay2 = amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .filter(d -> DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) >= 31 && DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) <= 60)
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 逾期61-90天未归还本金
        BigDecimal delayDay3 = amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .filter(d -> DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) >= 61 && DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) <= 90)
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 逾期91-180天未归还本金
        BigDecimal delayDay4 = amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .filter(d -> DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) >= 91 && DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) <= 180)
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        // 逾期180天以上未归还本金
        BigDecimal delayDay5 = amAccountMainInfoList.stream()
                .filter(d -> TransBizConstant.ACCOUNT_TYPE_06.equalsIgnoreCase(d.getAccountType()))
                .filter(d -> DateUtils.getDatePoor(nextProcessingDate, d.getPaymentDueDate()) >= 181)
                .map(AmAccountMainInfo::getCurrBalance).reduce(BigDecimal.ZERO, BigDecimal::add);
        cmInteCoLonInfo.setDelayDay1(delayDay1);
        cmInteCoLonInfo.setDelayDay2(delayDay2);
        cmInteCoLonInfo.setDelayDay3(delayDay3);
        cmInteCoLonInfo.setDelayDay4(delayDay4);
        cmInteCoLonInfo.setDelayDay5(delayDay5);
        //53 NORMAL_PRIN_BAL 正常本金余额
        cmInteCoLonInfo.setNormalPrinBal(principal);
        //38 OVDUE_FLG 逾期标志 4级分类 0 正常 1 逾期
        cmInteCoLonInfo.setOvdueFlg(ovdueFlg);
        // 非转分期的
        boolean cancelFlag = TransBizConstant.ACCOUNT_STATUS_9.equalsIgnoreCase(countAcct.getAccountStatus());
        if (!TransBizConstant.ACCOUNT_STATUS_6.equals(loanInfo.getLonStatusCd())) {
            String accountStatus = "1";//贷款状态代码 0 取消
            if (Objects.nonNull(loanInfo.getPayoffDt()) || cancelFlag) {
                //39 LON_STATUS_CD 贷款状态代码 1-正常 2-逾期 7-核销 8-正常结清 核销 > 逾期 > 正常
                accountStatus = "8";
                if (cancelFlag && "0".equalsIgnoreCase(cmInteCoLonInfo.getPaidTerm())) {
                    cmInteCoLonInfo.setPaidTerm("1");
                }
            } else if (null != amDelinquencyInfo) {
                accountStatus = "2";//逾期
            }
            //39 LON_STATUS_CD 贷款状态代码 1-正常 2-逾期 7-核销 8-正常结清 核销 > 逾期 > 正常
            cmInteCoLonInfo.setLonStatusCd(accountStatus);
        }
        //37 OVDUE_CNT 逾期次数 (按照客户账单统计，当期有逾期 + 1)
        int overNum = 0;
        if (!cancelFlag) {
            //统计客户该订单累计逾期几次
            overNum = extAmDelinquencyInfoMapper.groupByloanIdWithProducts(customerId, tenantId, dubilNo,xajSeriesProducts, etlEffectiveDate);
        }
        cmInteCoLonInfo.setOvdueCnt(BigDecimal.valueOf(overNum));
        // 处理中的贷款信息
        //TlDisbursementLog tlDisbursementLog = extTlDisbursementLogMapper.selectDisbursementByCondition(dubilNo, customerId, tenantId);
        //if (TransBizConstant.DISBURSEMENT_LOG_SUM_STATUS_O.equalsIgnoreCase(tlDisbursementLog.getSumStatus())) {
        //    // TODO 处理中的贷款信息供数
        //    cmInteCoLonInfo.setLonStatusCd("O");
        //}
        if (!StringUtils.isEmpty(cmInteCoLonInfo.getLonStatusCd()) && "7".equals(cmInteCoLonInfo.getLonStatusCd())){
            //兴安借7 = 提前结清  供数改为正常结清
            cmInteCoLonInfo.setLonStatusCd("8");
        }

        //54 OVDUE_PRIN_BAL 逾期本金余额
        cmInteCoLonInfo.setOvduePrinBal(ovdrPrincipal);
        //55 PUNISH_INT_AMT 罚息金额
        cmInteCoLonInfo.setPunishIntAmt(lgPenInter);
        //56 OWE_INT_AMT 欠息金额
        cmInteCoLonInfo.setOweIntAmt(countAcct.getInterestBalance());
        //57 HANG_INT_BAL 挂息金额
        cmInteCoLonInfo.setHangIntBal(BigDecimal.ZERO);

        //58 PUNISH_INT_INT_RATE 罚息利率
        cmInteCoLonInfo.setPunishIntIntRate(penaltyRate + "");
        //60 CURR_BAL 当期余额
        // 根据用户id 查询剩余本金--所有未还本金（包含未抛部分）
        //BigDecimal currBal = extAmLoanAccountInfoMapper.sumCurrBalByCustomerIdProducts(firstLevel.getCustomerId(), firstLevel.getTenantId(),
        //        Arrays.asList(TransBizConstant.ACCOUNT_STATUS_0, TransBizConstant.ACCOUNT_STATUS_1, TransBizConstant.ACCOUNT_STATUS_2), xahSeriesProducts);
        //cmInteCoLonInfo.setCurrBal(currBal);
        cmInteCoLonInfo.setCurrBal(cmInteCoLonInfo.getNormalPrinBal().add(cmInteCoLonInfo.getOvduePrinBal()));
        //61 CLCURR_CURR_BAL 折本币当期余额
        cmInteCoLonInfo.setClcurrCurrBal(cmInteCoLonInfo.getCurrBal());
        //62 YEAR_INT_RATE 年利率
        cmInteCoLonInfo.setYearIntRate(mainInfo.getInterestRate() + "");
        //63 LON_DIR_CD 贷款投向行业代码
        //64 ORG_CONTRI_RATIO 机构出资比例
        //65 LON_TYPE_CD 贷款类型代码 消费贷-0200 经营贷-0300
        if (pro.getTableType().equals(ReportingConstant.LOAN_TYPE_6)) {
            cmInteCoLonInfo.setLonTypeCd("0300");
        } else {
            cmInteCoLonInfo.setLonTypeCd("0205"); //兴安花 0200 兴安借 0205
        }
        //68 CURR_PROVIED_INT 当期已计提利息
        cmInteCoLonInfo.setCurrProviedInt(lgInter);
        //69 OFBS_OWE_INT_BAL 表外欠息余额
        cmInteCoLonInfo.setOfbsOweIntBal(ofbsOweIntBal);
        //获取下期还款日 10号以前当月 10号以后下个月
        int curDD = Integer.parseInt(DateUtils.formatDate(busiDate).substring(9, 10));
        if (curDD >= 10) {
            paymentDate = DateUtils.getDateByMonth(paymentDate, 1);
        }
        cmInteCoLonInfo.setNtxeRepayDt(paymentDate);


        BigDecimal maxDebt = BigDecimal.ZERO;
        maxDebt = maxDebt.add(principal).add(ovdrPrincipal);
        String currentYearFirst = DateUtils.format(DateUtils.getCurrentYearFirst(busiDate));
        String currentYear = currentYearFirst.substring(0, 4);
        //按照订单编号 贷款订单id 获取指定时间之后的贷款信息数据
        List<CmInteCoLonInfo> lonInfos = extCmInteCoLonInfoMapper.queryByDuBilNoLonInfos(currentYear, customerId, dubilNo, tenantId,xajSeriesLimitIds);

        // 当年累计余额
        BigDecimal yearNormalPrinBal = lonInfos.stream().map(CmInteCoLonInfo::getNormalPrinBal).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal yearOvduePrinBal = lonInfos.stream().map(CmInteCoLonInfo::getOvduePrinBal).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal yearAccrualBal = yearNormalPrinBal.add(yearOvduePrinBal).add(maxDebt);
        cmInteCoLonInfo.setYearAccumBal(yearAccrualBal);
        // 当年平均余额
        int dayOfYear = DateUtils.getDayOfYear(busiDate);
        cmInteCoLonInfo.setyAvgBal(yearAccrualBal.divide(new BigDecimal(dayOfYear), CommonContants.BIGDECIMAL_SCALE, BigDecimal.ROUND_HALF_UP));
        // 当季累计余额
        Date quarterFirstDate = DateUtils.getQuarterFirstDate(busiDate);
        BigDecimal quarterNormalPrinBal = lonInfos.stream()
                .filter(lon -> lon.getEtlDt().compareTo(quarterFirstDate) >= 0)
                .map(CmInteCoLonInfo::getNormalPrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal quarterOvduePrinBal = lonInfos.stream()
                .filter(lon -> lon.getEtlDt().compareTo(quarterFirstDate) >= 0)
                .map(CmInteCoLonInfo::getOvduePrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal seasonalAccrualBal = quarterNormalPrinBal.add(quarterOvduePrinBal).add(maxDebt);
        cmInteCoLonInfo.setQuarAccumBal(seasonalAccrualBal);
        int seasonDays = DateUtils.getDiffDays(quarterFirstDate, busiDate) + 1;
        // 当季平均余额
        cmInteCoLonInfo.setqAvgBal(seasonalAccrualBal.divide(new BigDecimal(seasonDays), CommonContants.BIGDECIMAL_SCALE, BigDecimal.ROUND_HALF_UP));
        // 当月累计余额
        Date monthFirstDate = DateUtils.getMonthStartTime(busiDate);
        BigDecimal monthNormalPrinBal = lonInfos.stream()
                .filter(lon -> lon.getEtlDt().compareTo(monthFirstDate) >= 0)
                .map(CmInteCoLonInfo::getNormalPrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal monthOvduePrinBal = lonInfos.stream()
                .filter(lon -> lon.getEtlDt().compareTo(monthFirstDate) >= 0)
                .map(CmInteCoLonInfo::getOvduePrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal monthAccrualBal = monthNormalPrinBal.add(monthOvduePrinBal).add(maxDebt);
        cmInteCoLonInfo.setMonAccumBal(monthAccrualBal);
        int dayOfMonth = DateUtils.getDayOfMonth(busiDate);
        // 当月平均余额
        cmInteCoLonInfo.setmAvgBal(monthAccrualBal.divide(new BigDecimal(dayOfMonth), CommonContants.BIGDECIMAL_SCALE, BigDecimal.ROUND_HALF_UP));

        //获取上一日的贷款信息
        Date yesterday = DateUtils.addDay(busiDate, -1);
        //73 MAX_DEBT 最大负债额
        BigDecimal lastMaxDebt = lonInfos.stream()
                .filter(lon -> DateUtils.format(lon.getEtlDt()).equalsIgnoreCase(DateUtils.format(yesterday)))
                .filter(lon -> lon.getDubilNo().equalsIgnoreCase(dubilNo))
                .sorted(Comparator.comparing(CmInteCoLonInfo::getEtlDt))
                .map(CmInteCoLonInfo::getMaxDebt)
                .findFirst().orElse(BigDecimal.ZERO);
        if (maxDebt.compareTo(lastMaxDebt) < 0) {
            maxDebt = lastMaxDebt;
        }
        cmInteCoLonInfo.setMaxDebt(maxDebt);

        // 根据贷款订单编号 交易日期（业务日期）分组查询贷款信息  todo:兴安借 累计提款笔数 不需要按照借据编号
        List<AmLoanMainInfoVo> list = extAmLoanMainInfoMapper.selectLoanInfoWithLoanIdProductsGroupByDay(tenantId, dubilNo, customerId, xajSeriesProducts);
        // 当日提款笔数
        cmInteCoLonInfo.setTodayDrawCnt(0);
        // 当日提款金额
        cmInteCoLonInfo.setTodayDrawAmt(BigDecimal.ZERO);
        // 累计提款笔数
        cmInteCoLonInfo.setAccumDrawCnt(0);
        if (CollectionUtils.isNotEmpty(list)) {
            AmLoanMainInfoVo amLoanMainInfoVo = list.stream().filter(a -> a.getPostingDate().equals(busiDate)).findAny().orElse(null);
            if (!Objects.isNull(amLoanMainInfoVo)) {
                // 当日提款笔数
                cmInteCoLonInfo.setTodayDrawCnt(amLoanMainInfoVo.getLoanCount());
                // 当日提款金额
                cmInteCoLonInfo.setTodayDrawAmt(amLoanMainInfoVo.getSumAmount());
            }
            Integer totalLoan = list.stream().filter(a -> a.getPostingDate().compareTo(etlEffectiveDate) > 0).map(AmLoanMainInfoVo::getLoanCount).reduce(0, Integer::sum);
            // 累计提款笔数
            cmInteCoLonInfo.setAccumDrawCnt(totalLoan);
        }
        bean.setCmInteCoLonInfo(cmInteCoLonInfo);
        return bean;
    }

    /**
     * 构建修改的产品额度变更记录
     * @param bean
     * @param tenantId
     * @param customerId
     * @param etlContractNumber
     * @param etlLimitId
     * @param etlSettleDate
     * @param etlExpiryDate
     * @param etlLoanId
     */
    public void buildUpdateLimitChangeLog(CmInteCoLonInfoBean bean, String tenantId, String customerId, String etlContractNumber, String etlLimitId, Date etlSettleDate, Date etlExpiryDate, String etlLoanId) {
        LimitChangeLogUpdate updateLimitChangeLog = bean.getUpdateLimitChangeLog();
        if (Objects.isNull(updateLimitChangeLog)) {
            updateLimitChangeLog = new LimitChangeLogUpdate();
            updateLimitChangeLog.setTenantId(tenantId);
            updateLimitChangeLog.setCustomerId(customerId);
            updateLimitChangeLog.setEtlContractNumber(etlContractNumber);
            updateLimitChangeLog.setEtlLimitId(etlLimitId);
        }
        if (Objects.nonNull(etlSettleDate)) {
            updateLimitChangeLog.setEtlSettleDate(etlSettleDate);
        }
        if (Objects.nonNull(etlExpiryDate)) {
            updateLimitChangeLog.setEtlExpiryDate(etlExpiryDate);
        }
        if (StringUtils.isNotBlank(etlLoanId)) {
            updateLimitChangeLog.setEtlLoanId(etlLoanId);
        }
        bean.setUpdateLimitChangeLog(updateLimitChangeLog);
    }

    /**
     * 转换成string
     * @param o
     * @return
     */
    public String getString(Object o) {
        return Objects.isNull(o) ? "" : o.toString();
    }

    @Override
    public CmInteCoLonRepayDtl assemRepayDtl(CmCustomerFirstLevel firstLevel) {
        if (null == firstLevel) {
            logger.info("未获取到客户一级信息");
            return null;
        }
        //兴安花系列产品
        List<String> xahSeriesProducts = BizTypeProducts.getXAHSeriesProducts();

        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(ReportingConstant.DEFAULT_ORG_NUMBER);

        //查询客户当天还款流水
        List<TlPaymentLog> paymentLogList = extTlPaymentLogMapper.selectByCollateDateAndCustomerIdProducts(firstLevel.getCustomerId(),
                firstLevel.getTenantId(), org.getToday(), ReportingConstant.PAYMENT_LOG_SUM_STATUS_S, xahSeriesProducts);
        if (CollectionUtils.isEmpty(paymentLogList)) {
            logger.info("未获取客户当日还款信息，客户编号: " + firstLevel.getCustomerId());
            return null;
        }

        CmLimitChangeLog latestDateInfo = iCustomerLimitInfoService.queryLatestEtlEffectDate(firstLevel.getTenantId(), firstLevel.getCustomerId(), xahSeriesProducts);
        Date etlEffectiveDate = latestDateInfo.getEtlEffectiveDate();
        //统计客户订单信息
        AmLoanAccountInfo countAcct = extAmLoanAccountInfoMapper.selectMaxLoanWithProducts(firstLevel.getCustomerId(), firstLevel.getTenantId(), xahSeriesProducts, etlEffectiveDate);
        if (Objects.isNull(countAcct) || Objects.isNull(countAcct.getCurrBalance())) {
            logger.warn("该用户{}数据有误，直接返回", firstLevel.getCustomerId());
            return null;
        }
        AmLoanMainInfo countMain = extAmLoanMainInfoMapper.selectByCountCustomerWithProducts(firstLevel.getCustomerId(), firstLevel.getTenantId(), xahSeriesProducts, etlEffectiveDate);
        if (Objects.isNull(countMain) || Objects.isNull(countMain.getFirstPaymentDate())) {
            logger.warn("该用户{}数据有误，直接返回", firstLevel.getCustomerId());
            return null;
        }
        //当期结清标志
        String isClear = "是";
        //查询客户所有订单 -----兴安花系列产品的所有订单
        List<AmLoanAccountInfo> amLoanAccountInfoList = extAmLoanAccountInfoMapper.selectRemainPrincipalAllByLoanIdWithProducts(firstLevel.getCustomerId(),
                paymentLogList.get(0).getChannel(), firstLevel.getTenantId(), xahSeriesProducts);
        for (AmLoanAccountInfo info : amLoanAccountInfoList) {
            if (TransBizConstant.ACCOUNT_STATUS_2.equals(info.getAccountStatus())) {
                isClear = "否";
                break;
            }
        }

        //查询客户最大逾期天数 客户最大逾期天数
        int delqDays = 0;
        AmDelinquencyInfo amDelinquencyInfo = extAmDelinquencyInfoMapper.getMaxDelqDaysInfoWithProducts(firstLevel.getCustomerId(), firstLevel.getTenantId(), TransBizConstant.ACCOUNT_STATUS_1, xahSeriesProducts);
        if (null != amDelinquencyInfo) {
            delqDays = amDelinquencyInfo.getDelqDays();
        }

        //当期还款日
        Date currPaymentDate = getCurrPaymentDate(org.getToday());

        CmInteCoLonRepayDtl cmInteCoLonRepayDtl = new CmInteCoLonRepayDtl();
        //1 数据日期
        cmInteCoLonRepayDtl.setEtlDt(org.getToday());
        //2 法人机构标识
        cmInteCoLonRepayDtl.setLpOrgNo("XIB");
        //3 交易流水编号
        cmInteCoLonRepayDtl.setTxSeqNo(paymentLogList.get(0).getSeqNo());
        // 最早的一笔借据编号
        //用户是否已经有对应的综合额度信息
        CmLimitChangeLog changeLog = iCustomerLimitInfoService.queryFirstLimitChangeLog(firstLevel.getTenantId(), firstLevel.getCustomerId(), xahSeriesProducts);
        if (null == changeLog) {
            logger.info("没有查询到首次额度生效日期，客户id:{},机构id:{}", firstLevel.getTenantId(), firstLevel.getCustomerId());
            return null;
        }
        //4 借据编号 客户最早的订单号
        cmInteCoLonRepayDtl.setDubilNo(changeLog.getEtlLoanId());
        //5 还款日期
        cmInteCoLonRepayDtl.setRepayDt(org.getToday());
        Date completeTime = paymentLogList.get(0).getCompleteTime();
        if (Objects.isNull(completeTime)) {
            completeTime = paymentLogList.get(0).getCreateTime();
        }
        //6 还款时间
        cmInteCoLonRepayDtl.setRepayTime(DateUtils.format(completeTime, DateUtils.DATETIME_PATTERN));
        //7 币种代码
        cmInteCoLonRepayDtl.setCurrCd("CNY");
        //8 当前还款期数

        int currRepayTerm = countingMonths(countMain.getFirstPaymentDate(), currPaymentDate);

        cmInteCoLonRepayDtl.setCurrRepayTerm(Long.valueOf(currRepayTerm));
        //9 本期延滞天数
        cmInteCoLonRepayDtl.setThTermDelayDays(Long.valueOf(delqDays));

        //计算还款本金利息罚息
        BigDecimal principalAmount = BigDecimal.ZERO;//本金
        BigDecimal interestAmount = BigDecimal.ZERO;//利息
        BigDecimal penaltyAmount = BigDecimal.ZERO;//罚息
        for (TlPaymentLog payLog : paymentLogList) {
            //根据流水查询还款分配表
            List<TlPaymentAllocationLog> allLogs = extTlPaymentAllocationLogMapper.selectBySeqNoAndTenantId(payLog.getSeqNo(), payLog.getTenantId());
            for (TlPaymentAllocationLog allocationLog : allLogs) {
                if (ReportingConstant.ACCOUNT_TYPE_06.equals(allocationLog.getConnectAccountType())) {
                    principalAmount = principalAmount.add(allocationLog.getPostingAmount());
                }
                if (ReportingConstant.ACCOUNT_TYPE_04.equals(allocationLog.getConnectAccountType())) {
                    interestAmount = interestAmount.add(allocationLog.getPostingAmount());
                }
                if (ReportingConstant.ACCOUNT_TYPE_11.equals(allocationLog.getConnectAccountType())) {
                    penaltyAmount = penaltyAmount.add(allocationLog.getPostingAmount());
                }
                if (ReportingConstant.ACCOUNT_TYPE_12.equals(allocationLog.getConnectAccountType())) {
                    penaltyAmount = penaltyAmount.add(allocationLog.getPostingAmount());
                }
            }
        }
        //10 本期实还本金
        cmInteCoLonRepayDtl.setThTermRepayPrin(principalAmount);
        //11 本期实还利息
        cmInteCoLonRepayDtl.setThTermRepayInt(interestAmount);
        //12 本期实还罚息
        cmInteCoLonRepayDtl.setThTermRepayPunishInt(penaltyAmount);
        //13 本期结清标志
        cmInteCoLonRepayDtl.setThTermPayoffMark(isClear);
        //14 来源平台编号
        cmInteCoLonRepayDtl.setSrcPlatNo("CCS");
        //15 REPAY_CLAIM_SITU_CD 索赔情况代码 TODO
        cmInteCoLonRepayDtl.setRepayClaimSituCd(" ");
        //16 REPAY_TYPE_CD	还款类型代码
        cmInteCoLonRepayDtl.setRepayTypeCd(getRepayType(paymentLogList, countAcct));
        cmInteCoLonRepayDtl.setTenantId(firstLevel.getTenantId());

        // '本期实还本金','本期实还利息', '本期实还罚息' 都大于0才需要供数（同时过滤只营销费的场景）
        if (principalAmount.compareTo(BigDecimal.ZERO) > 0 || interestAmount.compareTo(BigDecimal.ZERO) > 0 || penaltyAmount.compareTo(BigDecimal.ZERO) > 0) {
            return cmInteCoLonRepayDtl;
        }
        return null;
    }


    /**
     * @description: 生成还款明细信息 数据加工处理    (兴安借)
     * @author: shigongtai
     * @date: 2023/4/13 14:29
     */
    @Override
    public CmInteCoLonRepayDtl assemXajRepayDtl(CmInteCoLonRepayDtl repayDtl) throws TxnException {
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(ReportingConstant.DEFAULT_ORG_NUMBER);
        String dubilNo = repayDtl.getDubilNo();
        String tenantId = repayDtl.getTenantId();
        //获取客户一级信息
        CmCustomerFirstLevel firstLevel = customerService.getFirstLevelByCondition(repayDtl.getCustomerId(), org.getOrganizationId(), tenantId);
        if (null == firstLevel) {
            logger.info("未获取到客户一级信息");
            return null;
        }
        //兴安借系列产品
        List<String> xajSeriesProducts = BizTypeProducts.getXAJSeriesProducts();

        //统计客户订单信息
        AmLoanAccountInfo countAcct = extAmLoanAccountInfoMapper.selectByLoanId(dubilNo, firstLevel.getCustomerId(), firstLevel.getTenantId());
        if (Objects.isNull(countAcct) || Objects.isNull(countAcct.getCurrBalance())) {
            logger.warn("该用户{}数据有误，直接返回", firstLevel.getCustomerId());
            return null;
        }
        //借据信息统计
        AmLoanMainInfo countMain = extAmLoanMainInfoMapper.selectByLoanIdAndCusId(dubilNo, firstLevel.getCustomerId(), firstLevel.getTenantId());

        if (Objects.isNull(countMain) || Objects.isNull(countMain.getFirstPaymentDate())) {
            logger.warn("该用户{}数据有误，直接返回", firstLevel.getCustomerId());
            return null;
        }
        //当期结清标志
        String isClear = "是";
        if (TransBizConstant.ACCOUNT_STATUS_2.equals(countAcct.getAccountStatus())) {
            isClear = "否";
        }

        //查询客户最大逾期天数 客户最大逾期天数
        int delqDays = 0;
        //todo:兴安借 查询客户逾期信息
        AmDelinquencyInfo amDelinquencyInfo = extAmDelinquencyInfoMapper.getByLoanIdMaxDelqDaysInfoWithProducts(firstLevel.getCustomerId(), firstLevel.getTenantId(),dubilNo, TransBizConstant.ACCOUNT_STATUS_1, xajSeriesProducts);

        if (null != amDelinquencyInfo) {
            delqDays = amDelinquencyInfo.getDelqDays();
        }
        CmInteCoLonRepayDtl cmInteCoLonRepayDtl = new CmInteCoLonRepayDtl();
        //1 数据日期
        cmInteCoLonRepayDtl.setEtlDt(org.getToday());
        //2 法人机构标识
        cmInteCoLonRepayDtl.setLpOrgNo("XIB");
        //3 交易流水编号
        cmInteCoLonRepayDtl.setTxSeqNo(repayDtl.getTxSeqNo());
        //4 借据编号 客户最早的订单号
        cmInteCoLonRepayDtl.setDubilNo(countAcct.getLoanId());
        //5 还款日期
        cmInteCoLonRepayDtl.setRepayDt(repayDtl.getRepayDt());
        //6 还款时间
        cmInteCoLonRepayDtl.setRepayTime(repayDtl.getRepayTime());
        //7 币种代码
        cmInteCoLonRepayDtl.setCurrCd("CNY");
        //8 当前还款期数
        cmInteCoLonRepayDtl.setCurrRepayTerm(repayDtl.getCurrRepayTerm());
        //9 本期延滞天数
        cmInteCoLonRepayDtl.setThTermDelayDays(Long.valueOf(delqDays));
        //10 本期实还本金
        cmInteCoLonRepayDtl.setThTermRepayPrin(repayDtl.getThTermRepayPrin());
        //11 本期实还利息
        cmInteCoLonRepayDtl.setThTermRepayInt(repayDtl.getThTermRepayInt());
        //12 本期实还罚息
        cmInteCoLonRepayDtl.setThTermRepayPunishInt(repayDtl.getThTermRepayPunishInt());
        //13 本期结清标志
        cmInteCoLonRepayDtl.setThTermPayoffMark(isClear);
        //14 来源平台编号
        cmInteCoLonRepayDtl.setSrcPlatNo("CCS");
        //15 REPAY_CLAIM_SITU_CD 索赔情况代码 TODO
        cmInteCoLonRepayDtl.setRepayClaimSituCd(" ");
        //16 REPAY_TYPE_CD	还款类型代码
        cmInteCoLonRepayDtl.setRepayTypeCd(repayDtl.getRepayTypeCd());
        cmInteCoLonRepayDtl.setTenantId(firstLevel.getTenantId());

        // '本期实还本金','本期实还利息', '本期实还罚息' 都大于0才需要供数（同时过滤只营销费的场景）
        if (repayDtl.getThTermRepayPrin().compareTo(BigDecimal.ZERO) > 0 || repayDtl.getThTermRepayInt().compareTo(BigDecimal.ZERO) > 0 || repayDtl.getThTermRepayPunishInt().compareTo(BigDecimal.ZERO) > 0) {
            return cmInteCoLonRepayDtl;
        }
        return null;
    }

    private CmCustomerFirstLevel findFirstLevelCustomer(GaVoucherInfo gaVoucherInfo) {
        CmCustomerFirstLevel firstLevelCond = new CmCustomerFirstLevel();
        firstLevelCond.setCustomerId(gaVoucherInfo.getCustomerId());
        firstLevelCond.setOrganizationId(gaVoucherInfo.getOrganizationId());
        firstLevelCond.setTenantId(gaVoucherInfo.getTenantId());
        List<CmCustomerFirstLevel> firstLevels = extCmCustomerFirstLevelMapper.selectByCondition(firstLevelCond);
        if (firstLevels.isEmpty()) {
            logger.info("根据传票流水获取一级客户信息记录不存在");
            return null;
        }

        return firstLevels.get(0);
    }

    @Override
    public CmInteCoAcctntEntryDtl assemAcctntDtl(GaVoucherInfo gaVoucherInfo) throws TxnException {
        if (null == gaVoucherInfo) {
            logger.info("未获取到传票流水");
            return null;
        }

        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(ReportingConstant.DEFAULT_ORG_NUMBER);

        //获取一级信息
        CmCustomerFirstLevel customerFirstLevel = findFirstLevelCustomer(gaVoucherInfo);
        if (customerFirstLevel == null) {
            return null;
        }
        // 最早的一笔借据编号
        String minLoanId;
        String bizClassName;
        String productNo;
        String productName;
        if (BizTypeProducts.PRODUCT_XAF.equals(gaVoucherInfo.getProductId())) {
            minLoanId = gaVoucherInfo.getLoanId();
            bizClassName = BIZ_CLASS_NAME_XAF;
            productNo = PRODUCT_NO_XAF;
            productName = PRODUCT_NAME_XAF;
        } else if (BizTypeProducts.getXAHSeriesProducts().contains(gaVoucherInfo.getProductId())) {
            // 通过产品编号判断同系列有哪些产品编号
            List<String> seriesProducts = BizTypeProducts.getXAHSeriesProducts();
            //用户是否已经有对应的综合额度信息
            CmLimitChangeLog changeLog = iCustomerLimitInfoService.queryFirstLimitChangeLog(gaVoucherInfo.getTenantId(), gaVoucherInfo.getCustomerId(), seriesProducts);
            if(null == changeLog){
                logger.info("没有查询到首次额度生效日期，客户id:{},机构id:{}", gaVoucherInfo.getTenantId(), gaVoucherInfo.getCustomerId());
                return null;
            }
            minLoanId = changeLog.getEtlLoanId();
            // 防止重新授信后任未用信，产生溢缴款
            if (StringUtils.isBlank(minLoanId)) {
                List<CmLimitChangeLog> limitChangeLogs = iCustomerLimitInfoService.queryChangeLogs(Constants.DEFAULT_TENANT_ID, gaVoucherInfo.getCustomerId(), Constants.DEFAULT_PRODTCT_CODE);
                // 取最近一次的借据编号
                Optional<CmLimitChangeLog> firstOpt = limitChangeLogs.stream().sorted(Comparator.comparing(CmLimitChangeLog::getEtlExpiryDate).reversed())
                        .filter(log -> StringUtils.isNotBlank(log.getEtlLoanId())).findFirst();
                if (firstOpt.isPresent()) {
                    minLoanId = firstOpt.get().getEtlLoanId();
                }
            }
            bizClassName = BIZ_CLASS_NAME_XAH;
            productNo = PRODUCT_NO_XAH;
            productName = PRODUCT_NAME_XAH;
        } else if (BizTypeProducts.getXAJSeriesProducts().contains(gaVoucherInfo.getProductId())) {//兴安借
            minLoanId = gaVoucherInfo.getLoanId();  //获取贷款订单ID
            bizClassName = BIZ_CLASS_NAME_XAJ;
            productNo = PRODUCT_NO_XAJ;
            productName = PRODUCT_NAME_XAJ;
        }else {
            minLoanId = gaVoucherInfo.getLoanId();
            bizClassName = BIZ_CLASS_NAME_XAJ;
            productNo = PRODUCT_NO_XAJ;
            productName = PRODUCT_NAME_XAJ;
        }

        //获取订单信息
        AmLoanMainInfo amLoanMainInfo = extAmLoanMainInfoMapper.selectByLoanIdAndCusId(gaVoucherInfo.getLoanId(), gaVoucherInfo.getCustomerId(), gaVoucherInfo.getTenantId());

        //获取2级客户信息
        CmCustomerSecondLevel secondLevel = customerService.getSecondByChannelAndCustomerIdAndTensnId(amLoanMainInfo.getChannel(), amLoanMainInfo.getCustomerId(), amLoanMainInfo.getTenantId(), amLoanMainInfo.getProductId());

        CmInteCoAcctntEntryDtl acctntDtl = new CmInteCoAcctntEntryDtl();
        //1 ETL_DT	数据日期
        acctntDtl.setEtlDt(org.getToday());
        //2 LP_ORG_NO	法人机构标识
        acctntDtl.setLpOrgNo("XIB");
        //3 ECB_NO	交易参考编号（借据编号）
        acctntDtl.setEcbNo(StringUtils.isNotBlank(minLoanId) ? minLoanId : gaVoucherInfo.getLoanId());
        //4 TX_NO	交易编号（借据编号）
        acctntDtl.setTxNo(gaVoucherInfo.getLoanId());
        //5 ENTRY_NO 分录编号（交易流水）
        acctntDtl.setEntryNo(gaVoucherInfo.getId() + "");
        //6 CUST_NO	客户编号 身份证
        acctntDtl.setCustNo(customerFirstLevel.getIdNumber());
        //7 CORE_CUST_NO	核心客户编号
        acctntDtl.setCoreCustNo(customerFirstLevel.getEcifId());
        //8 CUST_NAME	客户名称
        acctntDtl.setCustName(customerFirstLevel.getChineseName());
        //9 BIZ_CLASS_NO	业务分类编号
        acctntDtl.setBizClassNo("3284");
        //10 BIZ_CLASS_NAME	业务分类名称
        acctntDtl.setBizClassName(bizClassName);
        //11 PRODUCT_NO	产品编号
        acctntDtl.setProductNo(productNo);
        //12 PRODUCT_NAME	产品名称
        acctntDtl.setProductName(productName);
        //13 SUBJECT_NO	科目编号
        acctntDtl.setSubjectNo(gaVoucherInfo.getSubjectId());
        //14 ACCTING_CLASS_NO	核算分类编号
        acctntDtl.setAcctingClassNo(" ");
        //15 APP_TYPE_CD	应用类型代码
        acctntDtl.setAppTypeCd(" ");

        if (gaVoucherInfo.getSign().equals("D")) {
            //16 DR_AMT	借方发生额
            acctntDtl.setDrAmt(gaVoucherInfo.getAmount());
            //18 DR_AMT_CNY	借方发生额折人民币
            acctntDtl.setDrAmtCny(gaVoucherInfo.getAmount());
        } else if (gaVoucherInfo.getSign().equals("C")) {
            //17 CR_AMT	贷方发生额
            acctntDtl.setCrAmt(gaVoucherInfo.getAmount());
            //19 CR_AMT_CNY	贷方发生额折人民币
            acctntDtl.setCrAmtCny(gaVoucherInfo.getAmount());
        }
        //20 EXEC_INT_RATE	执行利率 年利率
        //21 CORP_CHAR_CD
        acctntDtl.setCorpCharCd("8900");
        //22 CORP_CHAR_NAME	企业性质名称
        acctntDtl.setCorpCharName("其他个人");
        //23 DOM_OVERS_FLG	境内标志
        acctntDtl.setDomOversFlg("境内");
        //24 WIPE_ACCT_FLG	抹账标识 todo
        acctntDtl.setWipeAcctFlg(" ");
        //25 CHREM_ACCT_FLG	理财账户标志
        acctntDtl.setChremAcctFlg("否");
        //26 ACTL_VALUE_DT	实际起息日期 按照条件不填 TODO
        //27 ACTL_MATURE_DT	实际到期日期 按照条件不填 TODO
        //28 VALUE_DT	起息日期 按照条件不填 TODO
        //29 MATURE_DT	到期日期 按照条件不填 TODO
        CmCustomerExtInfo cmCustomerExtInfo = getUserExtendInfoConditions(gaVoucherInfo.getChannel(),gaVoucherInfo.getTenantId(),secondLevel.getCustomerId(),gaVoucherInfo.getProductId());
        if (null != cmCustomerExtInfo){
            //30 CUST_MGR_NO	客户经理编号
            acctntDtl.setCustMgrNo(cmCustomerExtInfo.getBankMgrNo());
        }else{
            //30 CUST_MGR_NO	客户经理编号
            acctntDtl.setCustMgrNo(secondLevel.getBankMgrNo());
        }
        //31 BELONG_ORG_NO	所属机构编号
        acctntDtl.setBelongOrgNo(gaVoucherInfo.getConOrgId());
        //32 ASSES_ORG_NO	考核机构编号
        acctntDtl.setAssesOrgNo(gaVoucherInfo.getConOrgId());
        //33 BELONG_BRCH_NO	所属分行编号
        //34 CURR_CD	币种代码
        acctntDtl.setCurrCd("CNY");
        //35 SRC_PLAT_NO	来源平台编号
        acctntDtl.setSrcPlatNo("CCS");
        // 36 ACCT_NO   设置核心记账账号
        this.setAcctNo(gaVoucherInfo, amLoanMainInfo, acctntDtl);

        //37 TX_CD	交易代码
        acctntDtl.setTxCd(gaVoucherInfo.getTxnCode());
        //38 TX_MEMO	交易备注
        acctntDtl.setTxMemo(gaVoucherInfo.getDescription());

        acctntDtl.setTenantId(gaVoucherInfo.getTenantId());
        return acctntDtl;
    }

    /**
     * 设置核心记账账号
     * @param gaVoucherInfo
     * @param amLoanMainInfo
     * @param acctntDtl
     * @throws TxnException
     */
    public void setAcctNo(GaVoucherInfo gaVoucherInfo, AmLoanMainInfo amLoanMainInfo, CmInteCoAcctntEntryDtl acctntDtl) throws TxnException {
        //36 ACCT_NO	核心记账账号 放款 还款需要送，计提不需要
        String customerId = gaVoucherInfo.getCustomerId();
        String tenantId = gaVoucherInfo.getTenantId();
        if (TransBizConstant.TXN_CODE_INSTSUM.equals(gaVoucherInfo.getTxnCode())) {
            // 兴安借
            String paramCode;
            if (BizTypeProducts.getXAJSeriesProducts().contains(gaVoucherInfo.getProductId())) {
                TlDisbursementLog tlDisbursementLog = extTlDisbursementLogMapper.selectDisbursementByCondition(gaVoucherInfo.getLoanId(), customerId, tenantId);
                if (Objects.equals(tlDisbursementLog.getPayeeAccountType(), TransBizConstant.CARD_TYPE_0)) {
                    // 本行卡
                    paramCode = TransBizConstant.INNER_BANK_DISBURSE_PERIOD_ACCT;
                } else {
                    // 他行卡
                    paramCode = TransBizConstant.OUTER_BANK_DISBURSE_PERIOD_ACCT;
                }
            } else {
                // 默认兴安花
                paramCode = TransBizConstant.REFUND_ACCT_NO + amLoanMainInfo.getThirdChannel();
            }
            //放款
            SystemParameterRes systemAcctNo = systemParameterServiceImpl.findByParamCode(paramCode, amLoanMainInfo.getTenantId());
            if (null != systemAcctNo) {
                acctntDtl.setAcctNo(systemAcctNo.getParamValue());
            }
        } else if ("P".equals(gaVoucherInfo.getTxnCode().substring(0, 1))) {
            // 兴安借
            String paramCode;
            if (BizTypeProducts.getXAJSeriesProducts().contains(gaVoucherInfo.getProductId())) {
                paramCode = TransBizConstant.XAJ_PAYMENT_ACCT_NO_JD;
            } else {
                TlGlInterfaceInfo tlGlInterfaceInfo = extTlGlInterfaceInfoMapper.selectByGlFlownoAndCusIdAndTenantId(gaVoucherInfo.getFlowno(), customerId, tenantId);
                TlPaymentAllocationLog tlPaymentAllocationLog = extTlPaymentAllocationLogMapper.selectByAccountIdAndTenantId(tlGlInterfaceInfo.getTxnAccountId(), tenantId);
                String seqNo = tlPaymentAllocationLog.getSeqNo();
                TlPaymentLog tlPaymentLog = extTlPaymentLogMapper.selectBySeqNoAndTenantIdAndCust(seqNo, tenantId, customerId);
                if (Objects.nonNull(tlPaymentLog) && Constant.THIRD_CHANNEL.equalsIgnoreCase(tlPaymentLog.getThirdChannel())) {
                    // 微信还款
                    paramCode = TransBizConstant.INNER_TRANSITIONAL_BANK_ACCT;
                }else {
                    // 兴安花默认
                    paramCode = TransBizConstant.PAYMENT_ACCT_NO;
                }
            }
            //还款
            SystemParameterRes systemAcctNo = systemParameterServiceImpl.findByParamCode(paramCode, amLoanMainInfo.getTenantId());
            if (null != systemAcctNo) {
                acctntDtl.setAcctNo(systemAcctNo.getParamValue());
            }
        }
    }

    @Override
    public CmInteCoImpairmentInfo assemImpairment(GaVoucherInfo gaVoucherInfo) throws TxnBizException {
        if (null == gaVoucherInfo) {
            logger.info("未获取到传票流水");
            return null;
        }

        CmInteCoImpairmentInfo impairmentInfo = new CmInteCoImpairmentInfo();
        //1 ACCOUNTING_YEAR	财政年度
        impairmentInfo.setAccountingYear(DateUtils.getYear(gaVoucherInfo.getBusinessDate()));
        //2 PERIOD_NAME	会计期间
        impairmentInfo.setPeriodName(DateUtils.format(gaVoucherInfo.getBusinessDate(), "yyyy-MM"));
        //3 ACCOUNTING_DATE	交易日期
        impairmentInfo.setAccountingDate(gaVoucherInfo.getBusinessDate());
        //4 CURRENCY_CODE	交易货币代码
        impairmentInfo.setCurrencyCode("CNY");
        //5 LEDGER_ID	帐套ID
        impairmentInfo.setLedgerId(2025);
        //6 SEGMENT1	机构
        impairmentInfo.setSegment1(gaVoucherInfo.getConOrgId());
        //7 SEGMENT2	责任中心
        impairmentInfo.setSegment2("999");
        //8 SHEET_FLAG	表内外标示
        if (gaVoucherInfo.getCategory().equals("2")) {
            impairmentInfo.setSheetFlag("OUT");
        } else {
            impairmentInfo.setSheetFlag("IN");
        }
        //9 SEGMENT3	科目
        impairmentInfo.setSegment3(gaVoucherInfo.getSubjectId());
        //10 SEGMENT4	产品
        impairmentInfo.setSegment4("CF21");
        //兴安借 供数产品编码 CF23
        if (BizTypeProducts.getXAJSeriesProducts().contains(gaVoucherInfo.getProductId())){
            impairmentInfo.setSegment4("CF23");
        }
        //11 SEGMENT5	条线
        impairmentInfo.setSegment5("90");
        //12 SEGMENT6	备用（项目）
        impairmentInfo.setSegment6("9999");
        //13 SEGMENT7	来源
        impairmentInfo.setSegment7("34");
        //14 SEGMENT8	COA备用1
        impairmentInfo.setSegment8("9");
        //15 SEGMENT9	COA备用2
        impairmentInfo.setSegment9("9");
        //16 SEGMENT10	COA备用3
        impairmentInfo.setSegment10("9");
        //17 SEGMENT11	COA备用4
        impairmentInfo.setSegment11("9");

        if (gaVoucherInfo.getSign().equals("D")) {
            //18 ENTERED_DR	过帐交易借方金额
            impairmentInfo.setEnteredDr(gaVoucherInfo.getAmount());
        } else if (gaVoucherInfo.getSign().equals("C")) {
            //19 ENTERED_CR	过帐交易贷方金额
            impairmentInfo.setEnteredCr(gaVoucherInfo.getAmount());
        }
        //20 SOURCE_ENTITY	来源实体
        impairmentInfo.setSourceEntity("XIB");
        //21 SOURCE_KEY	来源系统
        impairmentInfo.setSourceKey("CCS");
        //22 SOURCE_SECOND	二级来源
        impairmentInfo.setSourceSecond("INT");
        //23 DESCRIPTION	描述
        impairmentInfo.setDescription("CCS账务");
        //24 PROD_KEY1	备用KEY1
        impairmentInfo.setProdKey1(" ");
        //25 PROD_KEY2	备用KEY2
        impairmentInfo.setProdKey2(" ");
        //26 PROD_KEY3	备用KEY3
        impairmentInfo.setProdKey3(" ");
        //27 PROD_KEY4	备用KEY4
        impairmentInfo.setProdKey4(" ");
        //28 PROD_KEY5	备用KEY5
        impairmentInfo.setProdKey5(" ");

        impairmentInfo.setTenantId(gaVoucherInfo.getTenantId());
        return impairmentInfo;
    }

    @Override
    public AmlIATrading assemTrading(AmLoanMainInfo amLoanMainInfo) throws TxnBizException {
        if (null == amLoanMainInfo) {
            logger.info("未获取新增订单");
            return null;
        }
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(ReportingConstant.DEFAULT_ORG_NUMBER);

        //获取客户一级信息
        CmCustomerFirstLevel firstLevel = customerService.getFirstLevelByCondition(amLoanMainInfo.getCustomerId(), amLoanMainInfo.getOrganizationId(), amLoanMainInfo.getTenantId());

        //获取客户二级信息
        CmCustomerSecondLevel secondLevel = customerService.getSecondByChannelAndCustomerIdAndTensnId(amLoanMainInfo.getChannel(), amLoanMainInfo.getCustomerId(), amLoanMainInfo.getTenantId(), amLoanMainInfo.getProductId());

        String serialNumber = amLoanMainInfo.getSerialNumber();//流水号
        if (null == serialNumber) {
            serialNumber = SeqUtils.getRandomNumber(32);
        }
        AmlIATrading amlIATrading = new AmlIATrading();
        //1 ETL_DT	数据日期
        amlIATrading.setEtlDt(org.getToday());
        //2 BUSINESS_ID	业务标示号 业务流水号
        amlIATrading.setBusinessId(serialNumber);
        //3 TRADE_DATE	交易日期
        amlIATrading.setTradeDate(amLoanMainInfo.getTxnTime());
        logger.info("处理反洗钱信息（放款）交易时间是：{}", amLoanMainInfo.getTxnTime());
        //4 TRADE_TIME	交易时间
        amlIATrading.setTradeTime(amLoanMainInfo.getTxnTime());
        //5 SERIAL_NUMBER	流水号-与业务标志号相同
        if (serialNumber.length() > 32) {
            serialNumber = serialNumber.substring(serialNumber.length() - 32);
        }
        amlIATrading.setSerialNumber(serialNumber);
        //6 VOUCHER_NO	传票号
        amlIATrading.setVoucherNo(amLoanMainInfo.getLoanId());
        //7 SIURCE_TRADE_ID	源交易代码-与业务标志号相同
        String siurceTradeId = amLoanMainInfo.getContractId();
        if (null != siurceTradeId && siurceTradeId.length() > 10) {
            siurceTradeId = siurceTradeId.substring(siurceTradeId.length() - 10);
        }
        amlIATrading.setSiurceTradeId(siurceTradeId);
        //8 SOURCE_SYSTEM_TYPE	来源系统-CCS
        amlIATrading.setSourceSystemType("CCS");
        //9 TRADE_ORGANIZATION_ID	交易机构-客户所属机构，总账机构
        //10 TRADE_ORGANIZATION_COUNTRY	交易机构归属国家
        amlIATrading.setTradeOrganizationCountry("CHN");
        //11 TRADE_ORGANIZATION_REGION	交易机构归属行政区划
        amlIATrading.setTradeOrganizationRegion(secondLevel.getBankOrgNo());
        //12 CUSTOMER_ID	客户号
        amlIATrading.setCustomerId(firstLevel.getEcifId());
        //13 CUSTOMER_TYPE	客户类型-个人客户
        amlIATrading.setCustomerType("P");
        //14 CUSTOMER_NAME	客户名称
        amlIATrading.setCustomerName(firstLevel.getChineseName());
        // 通过产品编号判断同系列有哪些产品编号
        List<String> seriesProducts = BizTypeProducts.getSeriesProductIds(amLoanMainInfo.getProductId());
        //用户是否已经有对应的综合额度信息
        CmLimitChangeLog changeLog = iCustomerLimitInfoService.queryFirstLimitChangeLog(secondLevel.getTenantId(), secondLevel.getCustomerId(), seriesProducts);
        if(null == changeLog){
            logger.info("没有查询到首次额度生效日期，客户id:{},机构id:{}", secondLevel.getTenantId(), secondLevel.getCustomerId());
            return null;
        }
        //15 ACCOUNT	账号-借据号
        amlIATrading.setAccount(changeLog.getEtlContractNumber());
        //16 TRADE_MODE	交易方式-000151
        amlIATrading.setTradeMode("000151");
        //17 RMB_FOREIGN_CURRENCY_TAG	本外币标识-本
        amlIATrading.setRmbForeignCurrencyTag("1");
        //18 CASH_TRANSFER_TAG	现转标识-转
        amlIATrading.setCashTransferTag("01");
        //20 CHANNEL	交易渠道-其他电子银行
        amlIATrading.setChannel("07");
        //21 RECEIPT_PAYMENT_TAG	收付标识-放款付，还款收
        amlIATrading.setReceiptPaymentTag("02");
        //22  COUNTRY_ID	交易发生国别-CHN？
        amlIATrading.setCountryId("CHN");
        //23 REGION	交易发生行政区划-厦门
        amlIATrading.setRegion(secondLevel.getBankOrgNo());
        //24 DIRECTION_COUNTRY	交易方向国别-CHN
        amlIATrading.setDirectionCountry("CHN");
        //25 DIRECTION_REGION	交易方向行政区划-对方银行卡所在区划；同金融机构。
        amlIATrading.setDirectionRegion(secondLevel.getBankOrgNo());
        //26 FINANCIAL_INSTITUTION_COUNTRY	对方金融机构国家-CHN
        amlIATrading.setFinancialInstitutionCountry("CHN");
        //27 FINANCIAL_INSTITUTION_REGION	对方金融机构行政区划代码-对方银行卡所在区划；财付通、支付宝等第三方支付公司或银行 TODO
        amlIATrading.setFinancialInstitutionRegion(secondLevel.getBankOrgNo());
        //28 ORIGIN_USAGE	资金来源或用途-放款（消费贷）；还款
        amlIATrading.setOriginUsage("放款（消费贷）");
        //29 CURRENCY	币种
        amlIATrading.setCurrency("CNY");
        //30 AMOUNT	原币种金额
        amlIATrading.setAmount(amLoanMainInfo.getLoanAmount());
        //31 AMOUNT_CNY	金额折人民币
        amlIATrading.setAmountCny(amLoanMainInfo.getLoanAmount());
        //32 AMOUNT_USD	金额折美-按当天即期汇率 TODO
        amlIATrading.setAmountUsd(BigDecimal.ZERO);
        //34 PAIRING_FINANCIAL_SETUP_NAME	对方金融机构名称 TODO
        amlIATrading.setPairingFinancialSetupName(secondLevel.getBankOrgNo());
        //35 PAIRING_FINANCIAL_SETUP_TYPE	对方金融机构代码类型 TODO
        amlIATrading.setPairingFinancialSetupType(secondLevel.getBankOrgNo());
        //36 PAIRING_FINANCIAL_SETUP_ID	对方金融机构网点代码 TODO
        amlIATrading.setPairingFinancialSetupId(secondLevel.getBankOrgNo());
        //37 PAIRING_CUSTOMER_ID 交易对手客户号-本行有，非本行空 TODO
        amlIATrading.setPairingCustomerId(" ");
        //38 PAIRING_CUSTOMER_NAME	交易对手姓名-放款给商户信息，还款
        amlIATrading.setPairingCustomerName(PairingEnum.getNameByChannel(amLoanMainInfo.getThirdChannel()));
        //39 PAIRING_CUSTOMER_TYPE	交易对手客户类型-个人或公司 TODO
        amlIATrading.setPairingCustomerType("C");
        //40 PAIRING_INNER_ACCOUNT_TAG	交易对手内部帐标识-可为空
        amlIATrading.setPairingInnerAccountTag(" ");
        //41 PAIRING_IS_CUSTOMER_TAG	交易对手是否我行客户
        amlIATrading.setPairingIsCustomerTag("0");
        //42 BANK_COMMERCIAL_TENANT_TAG	是否我行商户
        amlIATrading.setBankCommercialTenantTag("C72".equals(amLoanMainInfo.getThirdChannel()) ? "1" : "0");
        //43 COMMERCIAL_TENANT_CODE	商户编码
        amlIATrading.setCommercialTenantCode(amLoanMainInfo.getMerchantId());
        //47 PAIRING_ACCOUNT	交易对手账号-还款统一银行卡，放款120002；网联给了账户，如果没给就填网联清算账户。
        amlIATrading.setPairingAccount(PairingEnum.getAccountByChannel(amLoanMainInfo.getThirdChannel()));

        //56 INTERNATIONAL_TRADE_TAG	是否跨境交易
        amlIATrading.setInternationalTradeTag("0");
        //60 IP	交易IP地址 TODO
        amlIATrading.setIp(" ");
        //61 MAC TODO
        amlIATrading.setMac(" ");
        //71 BUSINESS_TYPE	业务类型-仰章，仅包含消费、还款
        amlIATrading.setBusinessType("12");
        //72 BUSINESS_REMARKS	业务备注
        amlIATrading.setBusinessRemarks("消费");
        //75 NON_OTC_TYPE	非柜台交易方式-99
        amlIATrading.setNonOtcType("99");
        //76 NON_OTC_TYPE_DESCRIPTION	非柜台交易方式说明-兴安花
        amlIATrading.setNonOtcTypeDescription("兴安花");
        //77 NON_OTC_FACILITY_ID	非柜台交易介质的设备代码-交易手机号
        amlIATrading.setNonOtcFacilityId(secondLevel.getMobile());
        //78 BANK_PARMENTAUTHORITY_BTC 银行与支付机构之间的业务交易编码-网联等渠道的交易流水号 TODO 长度不够
        amlIATrading.setBankParmentauthorityBtc(" ");
        //79 CREDIT_CARD_TRADE_TAG	是否信用卡交易
        amlIATrading.setCreditCardTradeTag("0");
        //80 TRADE_TYPE	交易类型-其他，仰章代码值
        amlIATrading.setTradeType("03");
        //82 DESCRIPTION	摘要
        amlIATrading.setDescription(" ");
        //83 CALCULATION_TAG	是否计算
        amlIATrading.setCalculationTag("1");
        //90 IS_CASH_SETTLEMENT	是否现钞结汇(1-是，0-否)-否
        amlIATrading.setIsCashSettlement("0");
        //91 IS_CASH_SALE	是否现钞售汇(1-是，0-否)-否
        amlIATrading.setIsCashSale("0");
        //92 IS_CASH_EXCHANGE	是否外币现钞兑换(1-是，0-否)-否
        amlIATrading.setIsCashExchange("0");
        //93 IS_CASH_REMITTANCE	是否现金汇款(1-是，0-否)-否
        amlIATrading.setIsCashRemittance("0");
        //97 SETTLE_TYPE	业务类型，见详细表I_SETTLE_TYPE，同73
        amlIATrading.setSettleType("12");
        //98 SELF_DECL_FLAG	是否汇款申报(1-是，0-否)-否
        amlIATrading.setSelfDeclFlag("0");

        amlIATrading.setTenantId(amLoanMainInfo.getTenantId());
        //100 PAIRING_ACCOUNT_TYPE	交易对手账户类型-放款以银行卡来还，填007102银行卡
        amlIATrading.setPairingAccountType("007102");
        //兴安借  反洗钱信息供数  特殊处理
        if (BizTypeProducts.getXAJSeriesProducts().contains(changeLog.getProductId())){
            if (BankCardConstant.innerCardFlag(amLoanMainInfo.getCustomerAccountNumber())){
                //21 RECEIPT_PAYMENT_TAG	收付标识-放款付，还款收
                amlIATrading.setReceiptPaymentTag("01");
            }
            //100 交易对手账户类型PAIRING_ACCOUNT_TYPE，因交易对手账号都是银行卡，类型固定为120017；
            amlIATrading.setPairingAccountType("120017");
            //47 PAIRING_ACCOUNT	交易对手账号PAIRING_ACCOUNT，兴安借送银行卡号；   客户收款账号
            amlIATrading.setPairingAccount(amLoanMainInfo.getCustomerAccountNumber());
            //76 NON_OTC_TYPE_DESCRIPTION	非柜台交易方式说明-兴安借 todo:兴安借   待定
            amlIATrading.setNonOtcTypeDescription("兴安借");
        }
        return amlIATrading;
    }

    @Override
    public List<AmlIATrading> assemPaymentTrading(TlPaymentLog tlPaymentLog) throws TxnBizException {
        if (null == tlPaymentLog) {
            logger.info("未获取到还款流水");
            return null;
        }

        List<AmlIATrading> amlIATradings = new ArrayList<>();

        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(ReportingConstant.DEFAULT_ORG_NUMBER);

        //获取客户一级信息
        CmCustomerFirstLevel firstLevel = customerService.getFirstLevelByCondition(tlPaymentLog.getCustomerId(), tlPaymentLog.getOrganizationId(), tlPaymentLog.getTenantId());

        //获取客户二级信息
        CmCustomerSecondLevel secondLevel = customerService.getSecondByChannelAndCustomerIdAndTensnId(tlPaymentLog.getChannel(), tlPaymentLog.getCustomerId(), tlPaymentLog.getTenantId(), tlPaymentLog.getProductId());

        AmlIATrading amlIATrading = new AmlIATrading();
        //1 ETL_DT	数据日期
        amlIATrading.setEtlDt(org.getToday());
        //2 BUSINESS_ID	业务标示号 业务流水号
        amlIATrading.setBusinessId(tlPaymentLog.getSeqNo());
        //3 TRADE_DATE	交易日期
        amlIATrading.setTradeDate(tlPaymentLog.getLaunchTime());
        //4 TRADE_TIME	交易时间
        logger.info("处理反洗钱信息（还款）交易时间是：{}", tlPaymentLog.getLaunchTime());
        amlIATrading.setTradeTime(tlPaymentLog.getLaunchTime());
        //5 SERIAL_NUMBER	流水号-与业务标志号相同
        String serialNumber = tlPaymentLog.getPayId();//流水号
        if (null == serialNumber) {
            serialNumber = SeqUtils.getRandomNumber(32);
        }
        if (serialNumber.length() > 32) {
            serialNumber = serialNumber.substring(serialNumber.length() - 32);
        }

        amlIATrading.setSerialNumber(serialNumber);
        //6 VOUCHER_NO	传票号
        amlIATrading.setVoucherNo(tlPaymentLog.getPayId());
        //7 SIURCE_TRADE_ID	源交易代码-与业务标志号相同
        String siurceTradeId = tlPaymentLog.getRefNo();
        if (siurceTradeId.length() > 10) {
            siurceTradeId = siurceTradeId.substring(siurceTradeId.length() - 10);
        }
        amlIATrading.setSiurceTradeId(siurceTradeId);
        //8 SOURCE_SYSTEM_TYPE	来源系统-CCS
        amlIATrading.setSourceSystemType("CCS");
        //9 TRADE_ORGANIZATION_ID	交易机构-客户所属机构，总账机构
        //10 TRADE_ORGANIZATION_COUNTRY	交易机构归属国家
        amlIATrading.setTradeOrganizationCountry("CHN");
        //11 TRADE_ORGANIZATION_REGION	交易机构归属行政区划
        amlIATrading.setTradeOrganizationRegion(secondLevel.getBankOrgNo());
        //12 CUSTOMER_ID	客户号
        amlIATrading.setCustomerId(firstLevel.getEcifId());
        //13 CUSTOMER_TYPE	客户类型-个人客户
        amlIATrading.setCustomerType("P");
        //14 CUSTOMER_NAME	客户名称
        amlIATrading.setCustomerName(firstLevel.getChineseName());
        // 通过产品编号判断同系列有哪些产品编号
        List<String> seriesProducts = BizTypeProducts.getSeriesProductIds(tlPaymentLog.getProductId());
        //用户是否已经有对应的综合额度信息
        CmLimitChangeLog changeLog = iCustomerLimitInfoService.queryFirstLimitChangeLog(secondLevel.getTenantId(), secondLevel.getCustomerId(), seriesProducts);
        if(null == changeLog){
            logger.info("没有查询到首次额度生效日期，客户id:{},机构id:{}", secondLevel.getTenantId(), secondLevel.getCustomerId());
            return null;
        }
        //15 ACCOUNT	账号-借据号
        amlIATrading.setAccount(changeLog.getEtlContractNumber());
        //16 TRADE_MODE	交易方式-000151
        amlIATrading.setTradeMode("000151");
        //17 RMB_FOREIGN_CURRENCY_TAG	本外币标识-本
        amlIATrading.setRmbForeignCurrencyTag("1");
        //18 CASH_TRANSFER_TAG	现转标识-转
        amlIATrading.setCashTransferTag("01");
        //20 CHANNEL	交易渠道-其他电子银行
        amlIATrading.setChannel("07");
        //21 RECEIPT_PAYMENT_TAG	收付标识-放款付，还款收
        amlIATrading.setReceiptPaymentTag("01");
        //22  COUNTRY_ID	交易发生国别-CHN？
        amlIATrading.setCountryId("CHN");
        //23 REGION	交易发生行政区划-厦门
        amlIATrading.setRegion(secondLevel.getBankOrgNo());
        //24 DIRECTION_COUNTRY	交易方向国别-CHN
        amlIATrading.setDirectionCountry("CHN");
        //25 DIRECTION_REGION	交易方向行政区划-对方银行卡所在区划；同金融机构。 TODO
        amlIATrading.setDirectionRegion(secondLevel.getBankOrgNo());
        //26 FINANCIAL_INSTITUTION_COUNTRY	对方金融机构国家-CHN
        amlIATrading.setFinancialInstitutionCountry("CHN");
        //27 FINANCIAL_INSTITUTION_REGION	对方金融机构行政区划代码-对方银行卡所在区划；财付通、支付宝等第三方支付公司或银行 TODO
        amlIATrading.setFinancialInstitutionRegion(secondLevel.getBankOrgNo());
        //28 ORIGIN_USAGE	资金来源或用途-放款（消费贷）；还款
        amlIATrading.setOriginUsage("还款");
        //29 CURRENCY	币种
        amlIATrading.setCurrency("CNY");
        //30 AMOUNT	原币种金额
        amlIATrading.setAmount(tlPaymentLog.getAmount());
        //31 AMOUNT_CNY	金额折人民币
        amlIATrading.setAmountCny(tlPaymentLog.getAmount());
        //32 AMOUNT_USD	金额折美-按当天即期汇率 TODO
        amlIATrading.setAmountUsd(BigDecimal.ZERO);
        //34 PAIRING_FINANCIAL_SETUP_NAME	对方金融机构名称 TODO
        amlIATrading.setPairingFinancialSetupName(secondLevel.getBankOrgNo());
        //35 PAIRING_FINANCIAL_SETUP_TYPE	对方金融机构代码类型 TODO
        amlIATrading.setPairingFinancialSetupType(secondLevel.getBankOrgNo());
        //36 PAIRING_FINANCIAL_SETUP_ID	对方金融机构网点代码 TODO
        amlIATrading.setPairingFinancialSetupId(secondLevel.getBankOrgNo());
        //37 PAIRING_CUSTOMER_ID 交易对手客户号-本行有，非本行空
        amlIATrading.setPairingCustomerId(firstLevel.getEcifId());
        //38 PAIRING_CUSTOMER_NAME	交易对手姓名-放款给商户信息，还款
        amlIATrading.setPairingCustomerName(RepaymentEnum.ACQUIRING.getCname());
        //39 PAIRING_CUSTOMER_TYPE	交易对手客户类型-个人或公司
        amlIATrading.setPairingCustomerType("P");
        //40 PAIRING_INNER_ACCOUNT_TAG	交易对手内部帐标识-可为空
        amlIATrading.setPairingInnerAccountTag(" ");
        //41 PAIRING_IS_CUSTOMER_TAG	交易对手是否我行客户
        amlIATrading.setPairingIsCustomerTag("0");
        //42 BANK_COMMERCIAL_TENANT_TAG	是否我行商户
        amlIATrading.setBankCommercialTenantTag("0");
        //43 COMMERCIAL_TENANT_CODE	商户编码
        amlIATrading.setCommercialTenantCode("");
        //47 PAIRING_ACCOUNT	交易对手账号-还款统一银行卡，放款120002；网联给了账户，如果没给就填网联清算账户。
        amlIATrading.setPairingAccount(tlPaymentLog.getPayerAccount());
        //48 PAIRING_ACCOUNT_TYPE	交易对手账户类型-还款以银行卡来还，填120017银行卡；放款先不填
        amlIATrading.setPairingAccountType("120017");
        //56 INTERNATIONAL_TRADE_TAG	是否跨境交易
        amlIATrading.setInternationalTradeTag("0");
        //60 IP	交易IP地址 TODO
        amlIATrading.setIp(" ");
        //61 MAC TODO
        amlIATrading.setMac(" ");
        //71 BUSINESS_TYPE	业务类型-仰章，仅包含消费、还款
        amlIATrading.setBusinessType("12");
        //72 BUSINESS_REMARKS	业务备注
        amlIATrading.setBusinessRemarks("还款");
        //75 NON_OTC_TYPE	非柜台交易方式-99
        amlIATrading.setNonOtcType("99");
        //76 NON_OTC_TYPE_DESCRIPTION	非柜台交易方式说明-兴安花
        amlIATrading.setNonOtcTypeDescription("兴安花");
        //77 NON_OTC_FACILITY_ID	非柜台交易介质的设备代码-交易手机号
        amlIATrading.setNonOtcFacilityId(secondLevel.getMobile());
        //78 BANK_PARMENTAUTHORITY_BTC 银行与支付机构之间的业务交易编码-网联等渠道的交易流水号 TODO 长度不够
        amlIATrading.setBankParmentauthorityBtc(" ");
        //79 CREDIT_CARD_TRADE_TAG	是否信用卡交易
        amlIATrading.setCreditCardTradeTag("0");
        //80 TRADE_TYPE	交易类型-其他，仰章代码值
        amlIATrading.setTradeType("03");
        //82 DESCRIPTION	摘要
        amlIATrading.setDescription(" ");
        //83 CALCULATION_TAG	是否计算
        amlIATrading.setCalculationTag("1");
        //90 IS_CASH_SETTLEMENT	是否现钞结汇(1-是，0-否)-否
        amlIATrading.setIsCashSettlement("0");
        //91 IS_CASH_SALE	是否现钞售汇(1-是，0-否)-否
        amlIATrading.setIsCashSale("0");
        //92 IS_CASH_EXCHANGE	是否外币现钞兑换(1-是，0-否)-否
        amlIATrading.setIsCashExchange("0");
        //93 IS_CASH_REMITTANCE	是否现金汇款(1-是，0-否)-否
        amlIATrading.setIsCashRemittance("0");
        //97 SETTLE_TYPE	业务类型，见详细表I_SETTLE_TYPE，同73
        amlIATrading.setSettleType("12");
        //98 SELF_DECL_FLAG	是否汇款申报(1-是，0-否)-否
        amlIATrading.setSelfDeclFlag("0");

        amlIATrading.setTenantId(tlPaymentLog.getTenantId());

        //兴安借  反洗钱信息供数  特殊处理
        if (BizTypeProducts.getXAJSeriesProducts().contains(tlPaymentLog.getProductId())){
            if (BankCardConstant.innerCardFlag(tlPaymentLog.getPayerAccount())){
                //21 RECEIPT_PAYMENT_TAG	收付标识-放款付，还款收
                amlIATrading.setReceiptPaymentTag("02");
            }
            //100 交易对手账户类型PAIRING_ACCOUNT_TYPE，因交易对手账号都是银行卡，类型固定为120017；
            amlIATrading.setPairingAccountType("120017");
            //47 PAIRING_ACCOUNT	交易对手账号PAIRING_ACCOUNT，兴安借送银行卡号；   客户收款账号
            amlIATrading.setPairingAccount(tlPaymentLog.getPayerAccount());
            //76 NON_OTC_TYPE_DESCRIPTION	非柜台交易方式说明-兴安借 todo:兴安借   待定
            amlIATrading.setNonOtcTypeDescription("兴安借");
        }
        amlIATradings.add(amlIATrading);
        return amlIATradings;
    }

    @Override
    public CmInteCoLonRepayPlan assemPlan(CmCustomerFirstLevel firstLevel) throws TxnException {
        if (null == firstLevel) {
            logger.info("未获取到客户一级信息");
            return null;
        }
        //获取兴安花系列产品的产品编码
        List<String> xahSeriesProducts = BizTypeProducts.getXAHSeriesProducts();

        CmLimitChangeLog latestDateInfo = iCustomerLimitInfoService.queryLatestEtlEffectDate(firstLevel.getTenantId(), firstLevel.getCustomerId(), xahSeriesProducts);
        if (null == latestDateInfo) {
            return null;
        }
        Date etlEffectiveDate = latestDateInfo.getEtlEffectiveDate();
        //统计订单信息
        AmLoanMainInfo countMain = extAmLoanMainInfoMapper.selectByCountCustomerWithProducts(firstLevel.getCustomerId(), firstLevel.getTenantId(), xahSeriesProducts, etlEffectiveDate);
        if (null == countMain) {
            return null;
        }

        //获取当期业务时间
        PrOrganizationTable org = organizationTableService.findByOrId(TransBizConstant.DEFAULT_ORG_ID, firstLevel.getTenantId());
        Date bussinessDate = org.getToday();

        // 获取用户"首笔贷款额度信息"
        CmLimitChangeLog firstLimitInfo = iCustomerLimitInfoService.queryFirstLimitChangeLog(firstLevel.getTenantId(), firstLevel.getCustomerId(), xahSeriesProducts);
        if (null == firstLimitInfo) {
            logger.info("没有查询到首次额度生效日期，客户id:{},机构id:{}", firstLevel.getTenantId(), firstLevel.getCustomerId());
            return null;
        }
        Date etlSettleDate = firstLimitInfo.getEtlSettleDate();
        if (Objects.nonNull(etlSettleDate) && bussinessDate.compareTo(etlSettleDate) > 0) {
            logger.info("已经结清不需要再供数，客户id:{}", firstLevel.getCustomerId());
            return null;
        }
        Date lastPaymentDate = countMain.getLastPaymentDate();
        Date etlExpiryDate = firstLimitInfo.getEtlExpiryDate();

        Date nextProcessingDate = org.getNextProcessingDate();

        //当期还款日
        Date currPaymentDate = getCurrPaymentDate(nextProcessingDate);


        // 且完日之后的日期是1号，则需要供新的数据，其他日期则供上一天的数据
        if (!"1".equals(DateUtils.getDay(nextProcessingDate))) {
            CmInteCoLonRepayPlan cmInteCoLonRepayPlan = extCmInteCoLonRepayPlanMapper.selectByEtlDtAndDuBilNo(countMain.getLoanId(), firstLevel.getTenantId());
            if (Objects.nonNull(cmInteCoLonRepayPlan)) {
                cmInteCoLonRepayPlan.setEtlDt(bussinessDate);
                // 还款状态代码--默认填1
                cmInteCoLonRepayPlan.setRepayStatusCd("1");
                // 当期还款期数--默认填1
                cmInteCoLonRepayPlan.setCurrRepayTerm(1);
                return cmInteCoLonRepayPlan;
            }
        }

        // 获取客户贷款账户表 计算相关金额
        List<AmLoanAccountInfo> amLoanAccountInfoList = extAmLoanAccountInfoMapper.selectByCustProductsAndChannelAndStatus(firstLevel.getCustomerId(), null, firstLevel.getTenantId(),
                Arrays.asList(ReportingConstant.ACCOUNT_STATUS_0, ReportingConstant.ACCOUNT_STATUS_1, ReportingConstant.ACCOUNT_STATUS_2), xahSeriesProducts);

        List<String> loanIdList = new ArrayList<>();
        for (AmLoanAccountInfo amLoanAccountInfo : amLoanAccountInfoList) {
            if (!loanIdList.contains(amLoanAccountInfo.getLoanId())) {
                loanIdList.add(amLoanAccountInfo.getLoanId());
            }
        }

        BigDecimal totalAmount = BigDecimal.ZERO;//当期总金额
        BigDecimal principal = BigDecimal.ZERO;//当期本金
        BigDecimal inter = BigDecimal.ZERO;//当期利息(如果逾期包含罚息)
        if (CollectionUtils.isNotEmpty(amLoanAccountInfoList)) {
            Map<String, AmLoanAccountInfo> acctInfomap = amLoanAccountInfoList.stream().collect(Collectors.toMap(AmLoanAccountInfo::getLoanId, Function.identity()));

            List<AmRepaymentPlanInfo> planList =
                    extAmRepaymentPlanInfoMapper.selectByLoanIdListAndStatus(
                            loanIdList, firstLevel.getCustomerId(), firstLevel.getTenantId(),
                            Arrays.asList(TransBizConstant.LOAN_PLAN_STATUS_1, TransBizConstant.LOAN_PLAN_STATUS_2, TransBizConstant.LOAN_PLAN_STATUS_0));

            //计算欠款
            if (CollectionUtils.isNotEmpty(planList)) {
                for (AmRepaymentPlanInfo planInfo : planList) {
                    AmLoanAccountInfo loanAccountInfo = acctInfomap.get(planInfo.getLoanId());
                    if (currPaymentDate.compareTo(planInfo.getPaymentDueDate()) == 0) {
                        if (TransBizConstant.LOAN_PLAN_STATUS_1.equals(planInfo.getPlanStatus())) {
                            BigDecimal amt = planInfo.getPrincipalAmount().add(planInfo.getInterestAmount());
                            //总金额
                            totalAmount = totalAmount.add(amt);
                            BigDecimal pring = planInfo.getPrincipalAmount();
                            //本金
                            principal = principal.add(pring);
                            BigDecimal intr = planInfo.getInterestAmount();
                            //利息
                            inter = inter.add(intr);
                        } else if (TransBizConstant.LOAN_PLAN_STATUS_2.equals(planInfo.getPlanStatus())) {
                            DebtBean debtBean = debtCalculationService.getBalance(loanAccountInfo, Collections.singletonList(planInfo), nextProcessingDate, true, null, null, false);
                            //总欠款
                            totalAmount = totalAmount.add(debtBean.getTotalAmount());
                            //本金
                            principal = principal.add(debtBean.getPrincipalAmount());
                            //利息 = 利息 + 罚息
                            BigDecimal intr = debtBean.getInterestAmount().add(debtBean.getPenaltyAmount());
                            inter = inter.add(intr);
                        }
                    } else {
                        //还款日不等于当期的还款计算 只计算总欠款
                        if (TransBizConstant.LOAN_PLAN_STATUS_2.equals(planInfo.getPlanStatus())) {
                            DebtBean debtBean = debtCalculationService.getBalance(loanAccountInfo, Collections.singletonList(planInfo), nextProcessingDate, true, null, null, false);
                            //总欠款
                            totalAmount = totalAmount.add(debtBean.getTotalAmount());
                            //本金
                            principal = principal.add(debtBean.getPrincipalAmount());
                            //利息 = 利息 + 罚息
                            BigDecimal intr = debtBean.getInterestAmount().add(debtBean.getPenaltyAmount());
                            inter = inter.add(intr);
                        }
                    }
                }
            }
        }

        CmInteCoLonRepayPlan plan = new CmInteCoLonRepayPlan();
        //1 租户
        plan.setTenantId(firstLevel.getTenantId());
        //2 ETL_DT	数据日期
        plan.setEtlDt(bussinessDate);
        //3 LP_ORG_NO	法人机构标识
        plan.setLpOrgNo("XIB");
        // 最早的一笔借据编号
        //4 DUBIL_NO	借据编号
        plan.setDubilNo(firstLimitInfo.getEtlLoanId());
        //5 LON_TERM	贷款期数
        int loanTerm = this.tenor(countMain.getInterestStartDate(), countMain.getLastPaymentDate());
        plan.setLonTerm(Long.valueOf(loanTerm));
        //7 REPAY_STOP_DT	账单结束日期
        plan.setRepayStopDt(currPaymentDate);
        // 账单结束日期需 小于等于（最后还款日和额度有效期内的最大值）
        if (currPaymentDate.after(lastPaymentDate) && currPaymentDate.after(etlExpiryDate)) {
            plan.setRepayStopDt(etlExpiryDate.after(lastPaymentDate) ? etlExpiryDate : lastPaymentDate);
        }
        Date repayStopDt = plan.getRepayStopDt();
        //当期账单日
        Date statementDate = DateUtils.getMonthStartTime(repayStopDt);
        //6 REPAY_START_DT	账单开始日期
        plan.setRepayStartDt(statementDate);
        //8 CURR_CD	币种代码
        plan.setCurrCd("CNY");
        BillDetailsInquiryReq billDetailsInquiryReq = new BillDetailsInquiryReq();
        billDetailsInquiryReq.setTenantId(firstLevel.getTenantId());
        billDetailsInquiryReq.setSeqNo(SeqUtils.getRandomNumber(32));
        billDetailsInquiryReq.setChannel("channel01");
        //获取客户二级信息
        CmCustomerSecondLevel secondLevel = customerService.getSecondByChannelAndCustomerIdAndTensnId("channel01", firstLevel.getCustomerId(), firstLevel.getTenantId(), BizTypeProducts.XAH_PRODUCT);
        billDetailsInquiryReq.setUserId(secondLevel.getUserId());

        billDetailsInquiryReq.setQueryMonth(DateUtils.format(nextProcessingDate, "yyyyMM"));
        billDetailsInquiryReq.setProductIds(xahSeriesProducts);
        BillDetailsInquiryRes billDetailsInquiryRes = null;
        try {
            billDetailsInquiryRes = loanHandler.billDetailsInquir(billDetailsInquiryReq);
        } catch (Exception e) {
            logger.error("账单详情查询入参:{}", JSON.toJSONString(billDetailsInquiryReq));
            logger.error("账单详情查询错误:", e);
            throw new TxnException("账单详情查询错误");
        }

        BigDecimal shouldPayAmy = billDetailsInquiryRes.getTotalBalance();
        // 获取用户的总罚息
        BigDecimal penaltyBalance = extAmLoanAccountInfoMapper.getUserPenaltyBalance(firstLevel.getCustomerId(), firstLevel.getTenantId());
        // 当期总利息
        BigDecimal interest = billDetailsInquiryRes.getBillDetailList().stream()
                .filter(bill -> TransBizConstant.LOAN_PLAN_STATUS_1.equalsIgnoreCase(bill.getBillStatus()))
                .map(BillDetail::getInterestAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 利息+罚息总和
        BigDecimal intTotal = penaltyBalance.add(interest);

        BigDecimal prinTotal = shouldPayAmy.subtract(intTotal);
        //9 SHOULD_PAY_AMT	当期应还金额
        plan.setShouldPayAmt(shouldPayAmy);
        //10 PRIN_TOTAL	本金总额
        plan.setPrinTotal(prinTotal);
        //11 INT_TOTAL	利息总额
        plan.setIntTotal(intTotal);
        //12 SRC_PLAT_NO	来源平台编号
        plan.setSrcPlatNo("CCS");
        // 还款状态代码--默认填1
        plan.setRepayStatusCd("1");
        // 当期还款期数--默认填1
        plan.setCurrRepayTerm(1);
        return plan;
    }

    @Override
    public AmlIATrading assemAccrued(TlInterestAccrualLog accrualLog) throws TxnBizException {
        if (null == accrualLog) {
            logger.info("未获取到新增的计提信息");
            return null;
        }
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(ReportingConstant.DEFAULT_ORG_NUMBER);

        AmLoanAccountInfo countAcct = extAmLoanAccountInfoMapper.selectByLoanId(accrualLog.getLoanId(), accrualLog.getCustomerId(), accrualLog.getTenantId());
        //获取客户一级信息
        CmCustomerFirstLevel firstLevel = customerService.getFirstLevelByCondition(accrualLog.getCustomerId(), accrualLog.getOrganizationId(), accrualLog.getTenantId());

        //获取客户二级信息
        CmCustomerSecondLevel secondLevel = customerService.getSecondByChannelAndCustomerIdAndTensnId(accrualLog.getChannel(), accrualLog.getCustomerId(), accrualLog.getTenantId(), countAcct.getProductId());

        String serialNumber = SeqUtils.getSNByLength(32);

        AmlIATrading amlIATrading = new AmlIATrading();
        //1 ETL_DT	数据日期
        amlIATrading.setEtlDt(org.getToday());
        //2 BUSINESS_ID	业务标示号 业务流水号
        amlIATrading.setBusinessId(serialNumber);
        //3 TRADE_DATE	交易日期
        amlIATrading.setTradeDate(org.getToday());
        //4 TRADE_TIME	交易时间
        amlIATrading.setTradeTime(accrualLog.getCreateTime());
        //5 SERIAL_NUMBER	流水号-与业务标志号相同
        amlIATrading.setSerialNumber(serialNumber.substring(serialNumber.length() - 10));
        //6 VOUCHER_NO	传票号
        amlIATrading.setVoucherNo(serialNumber.substring(serialNumber.length() - 10));
        //7 SIURCE_TRADE_ID	源交易代码-与业务标志号相同
        amlIATrading.setSiurceTradeId(serialNumber.substring(serialNumber.length() - 10));
        //8 SOURCE_SYSTEM_TYPE	来源系统-CCS
        amlIATrading.setSourceSystemType("CCS");
        //9 TRADE_ORGANIZATION_ID	交易机构-客户所属机构，总账机构
        //10 TRADE_ORGANIZATION_COUNTRY	交易机构归属国家
        amlIATrading.setTradeOrganizationCountry("CHN");
        //11 TRADE_ORGANIZATION_REGION	交易机构归属行政区划
        amlIATrading.setTradeOrganizationRegion(secondLevel.getBankOrgNo());
        //12 CUSTOMER_ID	客户号
        amlIATrading.setCustomerId(firstLevel.getEcifId());
        //13 CUSTOMER_TYPE	客户类型-个人客户
        amlIATrading.setCustomerType("P");
        //14 CUSTOMER_NAME	客户名称
        amlIATrading.setCustomerName(firstLevel.getChineseName());

        // 通过产品编号判断同系列有哪些产品编号
        List<String> seriesProducts = BizTypeProducts.getSeriesProductIds(countAcct.getProductId());
        //用户是否已经有对应的综合额度信息
        CmLimitChangeLog changeLog = iCustomerLimitInfoService.queryFirstLimitChangeLog(secondLevel.getTenantId(), secondLevel.getCustomerId(), seriesProducts);
        if(null == changeLog){
            logger.info("没有查询到首次额度生效日期，客户id:{},机构id:{}", secondLevel.getTenantId(), secondLevel.getCustomerId());
            return null;
        }
        //15 ACCOUNT	账号-借据号
        amlIATrading.setAccount(changeLog.getEtlContractNumber());
        //16 TRADE_MODE	交易方式-000151
        amlIATrading.setTradeMode("000151");
        //17 RMB_FOREIGN_CURRENCY_TAG	本外币标识-本
        amlIATrading.setRmbForeignCurrencyTag("1");
        //18 CASH_TRANSFER_TAG	现转标识-转
        amlIATrading.setCashTransferTag("01");
        //20 CHANNEL	交易渠道-其他电子银行
        amlIATrading.setChannel("07");
        //21 RECEIPT_PAYMENT_TAG	收付标识-放款付，还款收,计提收
        amlIATrading.setReceiptPaymentTag("01");
        //22  COUNTRY_ID	交易发生国别-CHN？
        amlIATrading.setCountryId("CHN");
        //23 REGION	交易发生行政区划-厦门
        amlIATrading.setRegion(secondLevel.getBankOrgNo());
        //24 DIRECTION_COUNTRY	交易方向国别-CHN
        amlIATrading.setDirectionCountry("CHN");
        //25 DIRECTION_REGION	交易方向行政区划-对方银行卡所在区划；同金融机构。
        amlIATrading.setDirectionRegion(secondLevel.getBankOrgNo());
        //26 FINANCIAL_INSTITUTION_COUNTRY	对方金融机构国家-CHN
        amlIATrading.setFinancialInstitutionCountry("CHN");
        //27 FINANCIAL_INSTITUTION_REGION	对方金融机构行政区划代码-对方银行卡所在区划；财付通、支付宝等第三方支付公司或银行 TODO
        amlIATrading.setFinancialInstitutionRegion(secondLevel.getBankOrgNo());
        //28 ORIGIN_USAGE	资金来源或用途-放款（消费贷）；还款
        if (ReportingConstant.INTEREST_ACCRUAL_TYPE_66.equals(accrualLog.getAccountType())) {
            amlIATrading.setOriginUsage("计提利息");
        } else {
            amlIATrading.setOriginUsage("计提罚息");
        }
        //29 CURRENCY	币种
        amlIATrading.setCurrency("CNY");
        //30 AMOUNT	原币种金额
        amlIATrading.setAmount(accrualLog.getCurrentTotalAmount());
        //31 AMOUNT_CNY	金额折人民币
        amlIATrading.setAmountCny(accrualLog.getCurrentTotalAmount());
        //32 AMOUNT_USD	金额折美-按当天即期汇率 TODO
        amlIATrading.setAmountUsd(BigDecimal.ZERO);
        //34 PAIRING_FINANCIAL_SETUP_NAME	对方金融机构名称 TODO
        amlIATrading.setPairingFinancialSetupName(secondLevel.getBankOrgNo());
        //35 PAIRING_FINANCIAL_SETUP_TYPE	对方金融机构代码类型 TODO
        amlIATrading.setPairingFinancialSetupType(secondLevel.getBankOrgNo());
        //36 PAIRING_FINANCIAL_SETUP_ID	对方金融机构网点代码 TODO
        amlIATrading.setPairingFinancialSetupId(secondLevel.getBankOrgNo());
        //37 PAIRING_CUSTOMER_ID 交易对手客户号-本行有，非本行空 TODO
        amlIATrading.setPairingCustomerId(" ");
        //38 PAIRING_CUSTOMER_NAME	交易对手姓名-放款给商户信息，还款
        amlIATrading.setPairingCustomerName(" ");
        //39 PAIRING_CUSTOMER_TYPE	交易对手客户类型-个人或公司 TODO
        amlIATrading.setPairingCustomerType("P");
        //40 PAIRING_INNER_ACCOUNT_TAG	交易对手内部帐标识-可为空
        amlIATrading.setPairingInnerAccountTag(" ");
        //41 PAIRING_IS_CUSTOMER_TAG	交易对手是否我行客户
        amlIATrading.setPairingIsCustomerTag("0");
        //42 BANK_COMMERCIAL_TENANT_TAG	是否我行商户
        AmLoanMainInfo amLoanMainInfo = extAmLoanMainInfoMapper.selectByLoanId(accrualLog.getLoanId(), accrualLog.getCustomerId(), accrualLog.getTenantId(), accrualLog.getChannel());
        amlIATrading.setBankCommercialTenantTag("C72".equals(amLoanMainInfo.getThirdChannel()) ? "1" : "0");
        //43 COMMERCIAL_TENANT_CODE	商户编码
        //47 PAIRING_ACCOUNT	交易对手账号-还款统一银行卡，放款120002；网联给了账户，如果没给就填网联清算账户。
        amlIATrading.setPairingAccount("120002");

        //56 INTERNATIONAL_TRADE_TAG	是否跨境交易
        amlIATrading.setInternationalTradeTag("0");
        //60 IP	交易IP地址 TODO
        amlIATrading.setIp(" ");
        //61 MAC TODO
        amlIATrading.setMac(" ");
        //71 BUSINESS_TYPE	业务类型-仰章，仅包含消费、还款
        amlIATrading.setBusinessType("12");
        //72 BUSINESS_REMARKS	业务备注
        amlIATrading.setBusinessRemarks("消费");
        //75 NON_OTC_TYPE	非柜台交易方式-99
        amlIATrading.setNonOtcType("99");
        //76 NON_OTC_TYPE_DESCRIPTION	非柜台交易方式说明-兴安花
        amlIATrading.setNonOtcTypeDescription("兴安花");
        //77 NON_OTC_FACILITY_ID	非柜台交易介质的设备代码-交易手机号
        amlIATrading.setNonOtcFacilityId(secondLevel.getMobile());
        //78 BANK_PARMENTAUTHORITY_BTC 银行与支付机构之间的业务交易编码-网联等渠道的交易流水号 TODO 长度不够
        amlIATrading.setBankParmentauthorityBtc(" ");
        //79 CREDIT_CARD_TRADE_TAG	是否信用卡交易
        amlIATrading.setCreditCardTradeTag("0");
        //80 TRADE_TYPE	交易类型-其他，仰章代码值
        amlIATrading.setTradeType("03");
        //82 DESCRIPTION	摘要
        amlIATrading.setDescription(" ");
        //83 CALCULATION_TAG	是否计算
        amlIATrading.setCalculationTag("1");
        //90 IS_CASH_SETTLEMENT	是否现钞结汇(1-是，0-否)-否
        amlIATrading.setIsCashSettlement("0");
        //91 IS_CASH_SALE	是否现钞售汇(1-是，0-否)-否
        amlIATrading.setIsCashSale("0");
        //92 IS_CASH_EXCHANGE	是否外币现钞兑换(1-是，0-否)-否
        amlIATrading.setIsCashExchange("0");
        //93 IS_CASH_REMITTANCE	是否现金汇款(1-是，0-否)-否
        amlIATrading.setIsCashRemittance("0");
        //97 SETTLE_TYPE	业务类型，见详细表I_SETTLE_TYPE，同73
        amlIATrading.setSettleType("12");
        //98 SELF_DECL_FLAG	是否汇款申报(1-是，0-否)-否
        amlIATrading.setSelfDeclFlag("0");

        amlIATrading.setTenantId(accrualLog.getTenantId());
        //兴安借  反洗钱信息供数  特殊处理
        if (BizTypeProducts.getXAJSeriesProducts().contains(amLoanMainInfo.getProductId())){
            if (BankCardConstant.innerCardFlag(amLoanMainInfo.getCustomerAccountNumber())){
                //21 RECEIPT_PAYMENT_TAG	收付标识-放款付，还款收
                amlIATrading.setReceiptPaymentTag("02");
            }
            //100 交易对手账户类型PAIRING_ACCOUNT_TYPE，因交易对手账号都是银行卡，类型固定为120017；
            amlIATrading.setPairingAccountType("120017");
            //47 PAIRING_ACCOUNT	交易对手账号PAIRING_ACCOUNT，兴安借送银行卡号；   客户收款账号
            amlIATrading.setPairingAccount(amLoanMainInfo.getCustomerAccountNumber());
            //76 NON_OTC_TYPE_DESCRIPTION	非柜台交易方式说明-兴安借 todo:兴安借   待定
            amlIATrading.setNonOtcTypeDescription("兴安借");
        }
        return amlIATrading;
    }

    @Override
    public void createXibEndLog() {
        //清空 BDP_INTERFACE_JOB 监控接口表
        extBdpInterfaceJobMapper.deleteAll();

        //获取当前业务日期
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(TransBizConstant.DEFAULT_ORG_ID);
        Date busiDate = org.getToday();

        //1 插入 零售客户信息 cm_inte_co_cust_info
        int custInfoCount = extCmInteCoCustInfoMapper.countByEtlDt(busiDate);
        buildBdpInterfaceJobTable("cm_inte_co_cust_info", custInfoCount, busiDate);

        //2 插入 贷款授信信息 cm_inte_co_lon_crdt_info
        int lonCrdtCount = extCmInteCoLonCrdtInfoMapper.countByEtlDt(busiDate);
        buildBdpInterfaceJobTable("cm_inte_co_lon_crdt_info", lonCrdtCount, busiDate);

        //3 插入 贷款信息	cm_inte_co_lon_info
        int lonInfoCount = extCmInteCoLonInfoMapper.countByEtlDt(busiDate);
        buildBdpInterfaceJobTable("cm_inte_co_lon_info", lonInfoCount, busiDate);

        //4 插入 贷款还款计划	cm_inte_co_lon_repay_plan
        int planCount = extCmInteCoLonRepayPlanMapper.countByEtlDt(busiDate);
        buildBdpInterfaceJobTable("cm_inte_co_lon_repay_plan", planCount, busiDate);

        //5 插入 会计分录明细账	cm_inte_co_acctnt_entry_dtl
        int acctCount = extCmInteCoAcctntEntryDtlMapper.countByEtlDt(busiDate);
        buildBdpInterfaceJobTable("cm_inte_co_acctnt_entry_dtl", acctCount, busiDate);

        //6 插入 贷款还款明细 cm_inte_co_lon_repay_dtl
        int repayCount = extCmInteCoLonRepayDtlMapper.countByEtlDt(busiDate);
        buildBdpInterfaceJobTable("cm_inte_co_lon_repay_dtl", repayCount, busiDate);

        //7 插入 减值入账	cm_inte_co_impairment_info
        int impairment = extCmInteCoImpairmentInfoMapper.countByEtlDt(busiDate);
        buildBdpInterfaceJobTable("cm_inte_co_impairment_info", impairment, busiDate);

        //8 插入 反洗钱信息	aml_i_a_trading
        int amlCount = extAmlIATradingMapper.countByEtlDt(busiDate);
        buildBdpInterfaceJobTable("aml_i_a_trading", amlCount, busiDate);

        // 查询today生成免息期成报表数量
        int num = extTlFreeInterestTableMapper.getTotalFreeInterestNum(busiDate);
        buildBdpInterfaceJobTable("tl_free_interest_table", num, busiDate);

        // 查询busiDate生成贷款信息数量(借据维度)
        int num1 = extFtpInteCoLonMapper.getTotalLoanCiNum(busiDate);
        buildBdpInterfaceJobTable("cm_inte_co_lon_info_ci", num1, busiDate);

        // 查询busiDate生成还款详情数量(借据维度)
        int num2 = extFtpInteCoLonMapper.getTotalRepayDtlNum(busiDate);
        buildBdpInterfaceJobTable("cm_inte_co_lon_repay_dtl_ci", num2, busiDate);

        // 查询busiDate生成还款计划数量(借据维度)
        int num3 = extFtpInteCoLonMapper.getTotalRepayPlanNum(busiDate);
        buildBdpInterfaceJobTable("cm_inte_co_lon_repay_plan_ci", num3, busiDate);

        // 查询busiDate生成受托支付数量
        String today = DateUtils.format(busiDate, DateUtils.DATE_PATTERN_ANOTHER);
        int entrustmentCount = extMEastVStzfxxbMapper.getTotalEntrustment(today);
        buildBdpInterfaceJobTable("m_east_v_stzfxxb", entrustmentCount, busiDate);

        logger.debug("生成大数据监控数据结束...");


    }

    /**
     * 根据业务日期获取当期还款日
     *
     * @param busiDate
     * @return
     */
    private Date getCurrPaymentDate(Date busiDate) {
        //获取当期还款日
        Date statementDate = DateUtils.getThisMonthDate(busiDate, 1);
        //当期账单日为当前业务日期前一个账单日,如果业务日期<当月账单日，则账单日前后推一个月
        if (busiDate.compareTo(statementDate) < 0) {
            statementDate = DateUtils.getDateByMonth(statementDate, -1);
        }
        //通过还款日paymentDd，获取账单日期statementDate月份的还款日期paymentDate
        Date paymentDate = DateUtils.getThisMonthDate(statementDate, 10);
        if (statementDate.compareTo(paymentDate) > 0) {
            //如果账单日>还款日，则还款日往后推一个月
            paymentDate = DateUtils.getDateByMonth(paymentDate, 1);
        }
        return paymentDate;
    }

    /**
     * 生成大数据监控数据
     *
     * @param tableName
     * @param num
     * @param busiDate
     */
    @Transactional
    @Override
    public void buildBdpInterfaceJobTable(String tableName, Integer num, Date busiDate) {
        BdpInterfaceJob bdpInterfaceJob = new BdpInterfaceJob();
        bdpInterfaceJob.setInterfaceType("table");
        bdpInterfaceJob.setSrcSystem("CCS");
        bdpInterfaceJob.setSrcTable(tableName);
        bdpInterfaceJob.setCountNum(num);
        bdpInterfaceJob.setOdate(DateUtils.format(busiDate, DateUtils.DATE_PATTERN_ANOTHER));
        bdpInterfaceJob.setSrcStatus(ReportingConstant.STATUS_1);
        bdpInterfaceJob.setCreateTime(DateUtils.format(new Date(), DateUtils.DATETIME_PATTERN));
        bdpInterfaceJob.setTenantId("101");

        bdpInterfaceJobMapper.insertSelective(bdpInterfaceJob);

    }

    /**
     * 获取间隔月份
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    private int countingMonths(Date beginDate, Date endDate) {
        int months;
        int beginYear = Integer.parseInt(DateUtils.format(beginDate).substring(0, 4));
        int ennYear = Integer.parseInt(DateUtils.format(endDate).substring(0, 4));
        months = (ennYear - beginYear) * 12;

        int first = Integer.parseInt(DateUtils.format(beginDate).substring(5, 7));
        int last = Integer.parseInt(DateUtils.format(endDate).substring(5, 7));
        months = months + last - first + 1;
        return months;
    }

    /**
     * 获取授信合同号
     *
     * @param secondLevel
     * @return
     */
    private String getCreditContractNumber(CmCustomerSecondLevel secondLevel) {
        List<CmCustomerLimitInfo> cmCustomerLimitInfos = extCmCustomerLimitInfoMapper.selectCusLimitByCusIdAndOrgIdAndStatus(secondLevel.getOrganizationId(), secondLevel.getCustomerId(),
                CustomerConstant.STATUS_FAILURE, secondLevel.getTenantId());
        List<CmCustomerLimitInfo> newList = cmCustomerLimitInfos.stream().filter(x -> StringUtils.isNotBlank(x.getContractNumber()))
                .sorted(Comparator.comparing(CmCustomerLimitInfo::getCreateTime))
                .collect(Collectors.toList());
        return CollectionUtils.isNotEmpty(newList) ? newList.get(0).getContractNumber() : " ";
    }

    /**
     * 根据日期获取间隔期数
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    private int tenor(Date beginDate, Date endDate) {
        int months;
        int beginYear = Integer.parseInt(DateUtils.format(beginDate).substring(0, 4));
        int ennYear = Integer.parseInt(DateUtils.format(endDate).substring(0, 4));
        months = (ennYear - beginYear) * 12;
        int first = Integer.parseInt(DateUtils.format(beginDate).substring(5, 7));
        int last = Integer.parseInt(DateUtils.format(endDate).substring(5, 7));
        months = months + last - first;
        return months;
    }

    /**
     * 转换还款类型
     *
     * @param paymentLogList
     * @param countAcct
     * @return
     */
    private String getRepayType(List<TlPaymentLog> paymentLogList, AmLoanAccountInfo countAcct) {

        for (TlPaymentLog x : paymentLogList) {
            if (ReportingConstant.REPAYMENT_TYPE_PREPAY_CURR.equals(x.getPaymentType()) ||
                    ReportingConstant.REPAYMENT_TYPE_PREPAY.equals(x.getPaymentType()) ||
                    ReportingConstant.REPAYMENT_TYPE_PRETERMINTION.equals(x.getPaymentType()) ||
                    ReportingConstant.REPAYMENT_TYPE_BILLPREPAYCURR.equals(x.getPaymentType())
            ) {
                if (BigDecimal.ZERO.compareTo(countAcct.getCurrBalance()) < 0) {
                    return ReportingConstant.REPAYMENT_TYPE_PREPAY;
                }
                return ReportingConstant.REPAYMENT_TYPE_PRETERMINTION;
            }
        }
        return ReportingConstant.REPAYMENT_TYPE_PAY;
    }

    /**
     * 根据客户信息统计客户当日还款信息
     * 当日还款信息明细FTP供数-借据维度
     *
     * @param repayDtlCi
     * @return
     * @throws TxnException
     */
    @Override
    public CmInteCoLonRepayDtlCi assemRepayDtlCi(CmInteCoLonRepayDtlCi repayDtlCi) throws TxnException {
        PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(ReportingConstant.DEFAULT_ORG_NUMBER);
        // 数据日期
        repayDtlCi.setEtlDt(org.getToday());
        // 法人机构标识
        repayDtlCi.setLpOrgNo("XIB");
        // 币种代码
        repayDtlCi.setCurrCd("CNY");
        /* 不提供供数
        // 当前还款期数
        Long currRepayTerm = repayDtlCi.getCurrRepayTerm();
        // 本期延滞天数 根据loanid查询和当前期数查询
        // extAmDelinquencyInfoMapper.getDelqDaysInfoByLoanIdAndTenor(repayDtlCi.getDubilNo(), currRepayTerm);
        repayDtlCi.setThTermDelayDays(1L);

        //当期结清标志
        String isClear = "是";
        //查询订单订单
        AmRepaymentPlanInfo amRepaymentPlanInfo = extAmRepaymentPlanInfoMapper.selectByLoanIdAndTenor(customerId, tenantId, channel, loanId, currRepayTerm.intValue());
        // 7、8才是结清标志
        if (!Arrays.asList(TransBizConstant.LOAN_PLAN_STATUS_7,TransBizConstant.LOAN_PLAN_STATUS_8).contains(amRepaymentPlanInfo.getPlanStatus())) {
            isClear = "否";
        }
        // 本期结清标志
        repayDtlCi.setThTermPayoffMark(isClear);*/
        repayDtlCi.setSrcPlatNo("CCS");
        // 来源平台编号
        // 还款索赔情况代码
        repayDtlCi.setRepayClaimSituCd(" ");
        //获取订单信息
        String loanId = repayDtlCi.getDubilNo();
        String customerId = repayDtlCi.getCustomerId();
        String tenantId = repayDtlCi.getTenantId();
        AmLoanAccountInfo countAcct = extAmLoanAccountInfoMapper.selectByLoanId(loanId, customerId, tenantId);
        // 还款类型代码
        repayDtlCi.setRepayTypeCd(getRepayType(repayDtlCi.getRepayTypeCd(), countAcct));
        // '本期实还本金','本期实还利息', '本期实还罚息' 都大于0才需要供数（同时过滤只营销费的场景）
        BigDecimal principalAmount = repayDtlCi.getThTermRepayPrin();
        BigDecimal interestAmount = repayDtlCi.getThTermRepayInt();
        BigDecimal penaltyAmount = repayDtlCi.getThTermRepayPunishInt();
        if (principalAmount.compareTo(BigDecimal.ZERO) > 0 || interestAmount.compareTo(BigDecimal.ZERO) > 0 || penaltyAmount.compareTo(BigDecimal.ZERO) > 0) {
            return repayDtlCi;
        }
        return null;
    }

    /**
     * 贷款信息FTP供数-借据维度
     *
     * @param loanInfoCi
     * @return
     * @throws TxnException
     */
    @Override
    public CmInteCoLonInfoCi assemLoanInfoCi(CmInteCoLonInfoCi loanInfoCi) throws TxnBizException {
        String tenantId = loanInfoCi.getTenantId();
        PrOrganizationTable org = organizationTableService.findByOrId(TransBizConstant.DEFAULT_ORG_ID, tenantId);
        String productId = loanInfoCi.getProductId();
        String custNo = loanInfoCi.getCustNo();
        String dubilNo = loanInfoCi.getDubilNo();
        PrCreditLimitMapping prCreditLimitMapping = extPrCreditLimitMappingMapper.selectByTenIdAndProIdAndChannel(tenantId, loanInfoCi.getChannel(), productId);
        if (null == prCreditLimitMapping) {
            String message = MessageFormat.format("根据tenantId:{0},channel:{1},productId:{2},未找到对应的limitMapping", tenantId, loanInfoCi.getChannel(), productId);
            throw new TxnBizException(TxnRespCode.NO_DATA.getCode(), message);
        }
        //信用就医不会有多个
        CmCustomerLimitInfo limitInfo = extCmCustomerLimitInfoMapper.selectByTenIdAndCusIdAndLimitId(tenantId, custNo, prCreditLimitMapping.getLimitId());
        if (limitInfo == null || "".equals(limitInfo.getSeqNo())){
            return null;
        } else {
            loanInfoCi.setCrdtContNo(limitInfo.getContractNumber());
            loanInfoCi.setLmtNo(limitInfo.getLimitId());
        }
        Date busiDate = org.getToday();
        //1 ETL_DT 数据日期
        loanInfoCi.setEtlDt(busiDate);
        //2 LP_ORG_NO 法人机构标识
        loanInfoCi.setLpOrgNo("XIB");
        //10 SUBJECT_NO 科目编号
        loanInfoCi.setSubjectNo("11400301");
        //11 LEVEL5_CLASS_CD 五级分类代码
        //12 LEVEL5_CLASS_NAME 五级分类名称
        //13 LEVEL10_CLASS_CD 十级分类代码
        //14 LEVEL10_CLASS_NAME 十级分类名称
        //15 BIZ_CLASS_NO 业务分类编号
        loanInfoCi.setBizClassNo("3284");
        //16 BIZ_CLASS_NO 业务分类名称
        loanInfoCi.setBizClassName("个人消费业务");
        //17 PRODUCT_NO 产品编号
        loanInfoCi.setProductNo("CF21");
        //18 PROD_NAME 产品名称
        loanInfoCi.setProdName("兴安花");
        AmLoanMainInfo countMain = extAmLoanMainInfoMapper.selectByLoanIdAndCusId(dubilNo, custNo, tenantId);
        //20 MATURE_DT 到期日期 最后一期还款日
        //当前系统日期如果大于最后一期还款日，则时间为当前系统日期年月，日期为10号
        if (busiDate.after(countMain.getLastPaymentDate())) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(busiDate);
            //系统日期和最后一期还款日月份相同
            if (DateUtils.getMonth(busiDate).equals(DateUtils.getMonth(countMain.getLastPaymentDate()))) {
                //时间为系统日期的下一个月10号
                cal.add(Calendar.MONTH, 1);
            }
            //时间为当前系统日期年月，日期为10号
            int year = cal.get(Calendar.YEAR);
            int month = cal.get(Calendar.MONTH);
            cal.set(year, month, 10);
            loanInfoCi.setMatureDt(cal.getTime());
        } else {
            loanInfoCi.setMatureDt(countMain.getLastPaymentDate());
        }
        //判断是否兴安借产品
        if (BizTypeProducts.getXAJSeriesProducts().contains(productId)){
            loanInfoCi.setProdName("兴安借");
            loanInfoCi.setProductNo("CF23");
            //还款计划 查询最后一期还款日
            AmRepaymentPlanInfo plan = extAmRepaymentPlanInfoMapper.queryMaxPaymentDueDate(dubilNo, custNo, tenantId);
            if (plan!= null && plan.getPaymentDueDate()!=null){
                //贷款到期日 取最后一期还款日
                loanInfoCi.setMatureDt(plan.getPaymentDueDate());
            }
        }
        AmLoanMainInfo mainInfo = extAmLoanMainInfoMapper.selectByLoanIdAndTenantId(dubilNo, tenantId);
        //获取产品信息
        PrProductTable pro = productTableService.findProByProIdAndOrgId(mainInfo.getProductId(), mainInfo.getOrganizationId(), mainInfo.getTenantId());
        //26 MAX_GRACE_PERIOD 最大宽限期
        loanInfoCi.setMaxGracePeriod(pro.getGraceDays() + "");

        List<String> xahSeriesProducts = BizTypeProducts.getSeriesProductIds(productId);
        CmLimitChangeLog latestDateInfo=iCustomerLimitInfoService.queryLatestEtlEffectDate(tenantId, countMain.getCustomerId(), xahSeriesProducts);
        // 获取最大逾期信息和最早逾期日
        AmDelinquencyInfo amDelinquencyInfo = extAmDelinquencyInfoMapper.getDelqDaysInfo(dubilNo, custNo, tenantId, TransBizConstant.ACCOUNT_STATUS_1,latestDateInfo.getEtlEffectiveDate());
        if (null != amDelinquencyInfo) {
            //27 OVDUE_BEGIN_DT 首次逾期日期 未关闭延滞交易账户
            loanInfoCi.setOvdueBeginDt(amDelinquencyInfo.getDelqDate());
            //28 MAX_OVDUE_DAYS 当前逾期天数
            loanInfoCi.setMaxOvdueDays(amDelinquencyInfo.getDelqDays());
        }

        //29 LON_USAGE_CD 借款用途代码
        loanInfoCi.setLonUsageCd("A99");
        //30 LON_USAGE_NAME 借款用途名称
        loanInfoCi.setLonUsageName("其他");
        //31 REPAY_WAY_CD 还款方式代码 02 等额本息
        loanInfoCi.setRepayWayCd("02");
        //32 REPAY_WAY_NAME 还款方式名称
        loanInfoCi.setRepayWayName("等额本息");
        // 根据借据编号获取最大日利率
        AmLoanMainInfo countMain2 = extAmLoanMainInfoMapper.getMaxDailyRateByLoanId(dubilNo, custNo, tenantId);
        // 日利率和罚息利率取值是正常和逾期的最大值，如果查询不到，则默认值为0
        BigDecimal actualDailyRate = BigDecimal.ZERO;
        if (null != countMain2 && null != countMain2.getActualDailyRate()) {
            actualDailyRate = countMain2.getActualDailyRate();
        }
        //33 DAY_INT_RATE 日利率 最大日利率
        loanInfoCi.setDayIntRate(actualDailyRate + "");
        //34 INT_RATE_TYPE_CD 利率类型代码 0-日利率
        loanInfoCi.setIntRateTypeCd("0");
        //35 PRIN_REPAY_FREQ_CD 本金还款频率代码 0-月
        loanInfoCi.setPrinRepayFreqCd("0");
        //36 INT_REPAY_FREQ_CD 利息还款频率代码 0-月
        loanInfoCi.setIntRepayFreqCd("0");
        //40 GUAR_WAY_CD 担保方式代码
        loanInfoCi.setGuarWayCd("400");
        //获取2级客户信息
        CmCustomerSecondLevel secondLevel = customerService.getSecondByChannelAndCustomerIdAndTensnId(loanInfoCi.getChannel(), custNo, tenantId, productId);
        //45 CUST_MGR_NO 客户经理编号
        //46 CUST_MGR_NAME 客户经理名称
        loanInfoCi.setCustMgrNo(secondLevel.getBankMgrNo());
        //47 BELONG_ORG_NO 所属机构编号
        //48 BELONG_ORG_NAME 所属机构名称
        loanInfoCi.setBelongOrgNo(secondLevel.getBankOrgNo());
        //49 ASSES_ORG_NO 考核机构编号
        //50 ASSES_ORG_NAME 考核机构名称
        loanInfoCi.setAssesOrgNo(secondLevel.getBankOrgNo());
        //51 SRC_PLAT_NO 来源平台编号
        loanInfoCi.setSrcPlatNo("CCS");
        //52 CURR_CD 币种代码
        loanInfoCi.setCurrCd("CNY");

        BigDecimal ofbsOweIntBal = BigDecimal.ZERO;//表外欠息余额
        BigDecimal principal = BigDecimal.ZERO;//正常本金 所有已抛未还本金 （不包含逾期本金）
        BigDecimal ovdrPrincipal = BigDecimal.ZERO; //逾期本金
        String ovdueFlg = "0";//0 正常

        // 获取客户贷款账户表 计算相关金额
        AmLoanAccountInfo acc = extAmLoanAccountInfoMapper.selectByLoanIdForBatch(dubilNo);
        boolean cancelFlag = false;
        if (null != acc) {
            String accountStatus = acc.getAccountStatus();
            if (ReportingConstant.ACCOUNT_STATUS_2.equals(accountStatus)) {
                ovdueFlg = "1";//逾期
            }
            // 1-非应计
            if (StringUtils.equals(acc.getNonAccrualsFlag(), TransBizConstant.NON_ACCRUALS_FLA_1)
                    && Arrays.asList(ReportingConstant.ACCOUNT_STATUS_0, ReportingConstant.ACCOUNT_STATUS_1, ReportingConstant.ACCOUNT_STATUS_2).contains(accountStatus)) {
                // interest_balance + penalty_balance + compound_balance
                ofbsOweIntBal = ofbsOweIntBal.add(acc.getInterestBalance()).add(acc.getPenaltyBalance()).add(acc.getCompoundBalance());
            }
            cancelFlag = TransBizConstant.ACCOUNT_STATUS_9.equalsIgnoreCase(accountStatus);
        }
        // 获取正常本金和逾期本金
        List<AmLoanAccountInfo> accountInfos = extAmLoanAccountInfoMapper.selectLoanAcctPrinBal(mainInfo.getCustomerId(), mainInfo.getChannel(), mainInfo.getTenantId(), dubilNo);
        principal = accountInfos.stream()
                // payoffDate 是空的直接统计，不是空的统计结清日期为today的数据
                .filter(a -> Objects.isNull(a.getPayoffDate()) || (Objects.nonNull(a.getPayoffDate()) && busiDate.compareTo(a.getPayoffDate()) <= 0))
                .map(AmLoanAccountInfo::getNormalPrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        ovdrPrincipal = accountInfos.stream()
                .filter(a -> Objects.isNull(a.getPayoffDate()) || (Objects.nonNull(a.getPayoffDate()) && busiDate.compareTo(a.getPayoffDate()) <= 0))
                .map(AmLoanAccountInfo::getOvduePrinBal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 逾期金额大于0
        if (ovdrPrincipal.compareTo(BigDecimal.ZERO) > 0) {
            ovdueFlg = "1";//逾期
        }
        //38 OVDUE_FLG 逾期标志 4级分类 0 正常 1 逾期
        loanInfoCi.setOvdueFlg(ovdueFlg);
        // 非转分期的
        if (!TransBizConstant.ACCOUNT_STATUS_6.equals(loanInfoCi.getLonStatusCd())) {
            String accountStatus = "1";//贷款状态代码 0
            if (Objects.nonNull(loanInfoCi.getPayoffDt()) || cancelFlag) {
                //39 LON_STATUS_CD 贷款状态代码 1-正常 2-逾期 7-核销 8-正常结清 核销 > 逾期 > 正常
                accountStatus = "8";
                if (cancelFlag && "0".equalsIgnoreCase(loanInfoCi.getPaidTerm())) {
                    loanInfoCi.setPaidTerm("1");
                }
            } else if (null != amDelinquencyInfo) {
                accountStatus = "2";//逾期
            }
            //39 LON_STATUS_CD 贷款状态代码 1-正常 2-逾期 7-核销 8-正常结清 核销 > 逾期 > 正常
            loanInfoCi.setLonStatusCd(accountStatus);
        }
        if (cancelFlag) {
            loanInfoCi.setOvdueCnt(BigDecimal.ZERO);
        }
        //判断是否兴安借产品
        if (BizTypeProducts.getXAJSeriesProducts().contains(productId)){
            // 处理中的贷款信息
            //TlDisbursementLog tlDisbursementLog = extTlDisbursementLogMapper.selectDisbursementByCondition(dubilNo, custNo, tenantId);
            //if (TransBizConstant.DISBURSEMENT_LOG_SUM_STATUS_O.equalsIgnoreCase(tlDisbursementLog.getSumStatus())) {
            //    // TODO 处理中的贷款信息供数
            //    loanInfoCi.setLonStatusCd("O");
            //}
            if ("7".equals(loanInfoCi.getLonStatusCd())){
                //39 LON_STATUS_CD 贷款状态代码 1-正常 2-逾期 7-核销 8-正常结清 核销 > 逾期 > 正常
                //兴安借7 = 提前结清  供数改为正常结清
                loanInfoCi.setLonStatusCd("8");
            }
        }
        //53 NORMAL_PRIN_BAL 正常本金余额
        loanInfoCi.setNormalPrinBal(principal);
        //54 OVDUE_PRIN_BAL 逾期本金余额
        loanInfoCi.setOvduePrinBal(ovdrPrincipal);
        //查询罚息累计账户
        //获取当期还款日
        Date paymentDate = getCurrPaymentDate(busiDate);
        BigDecimal lgPenInter = BigDecimal.ZERO;//累计罚息
        BigDecimal lgInter = BigDecimal.ZERO;//计提利息
        // 根据借据编号查询客户下所有正常计提的累计账户
        List<AmInterestAccrualInfo> amInterestAccrualInfoList = extAmInterestAccrualInfoMapper.selectAllAccuAcct(dubilNo, custNo, tenantId,
                null, Arrays.asList(TransBizConstant.ACCOUNT_STATUS_1));
        if (CollectionUtils.isNotEmpty(amInterestAccrualInfoList)) {
            for (AmInterestAccrualInfo interestAccrualInfo : amInterestAccrualInfoList) {
                if (TransBizConstant.INTEREST_ACCRUAL_TYPE_10.equals(interestAccrualInfo.getAccountType())) {
                    lgPenInter = lgPenInter.add(interestAccrualInfo.getAccrualTotalAccruInterest());
                }
                if (TransBizConstant.INTEREST_ACCRUAL_TYPE_66.equals(interestAccrualInfo.getAccountType())) {
                    // 每个月9号需要特殊处理，ACCOUNT_STATUS会变成8-已完成计息
                    if (DateUtils.addDay(paymentDate, -1).equals(busiDate)) {
                        List<AmInterestAccrualInfo> list = extAmInterestAccrualInfoMapper.selectAllAccuAcct(dubilNo, custNo, tenantId,
                                null, Arrays.asList(TransBizConstant.ACCOUNT_STATUS_8));
                        if (CollectionUtils.isNotEmpty(list)) {
                            for (AmInterestAccrualInfo a : list) {
                                lgInter = lgInter.add(a.getAccrualTotalAccruInterest());
                            }
                        }
                    } else {
                        lgInter = lgInter.add(interestAccrualInfo.getAccrualTotalAccruInterest());
                    }
                }
            }
        }
        //55 PUNISH_INT_AMT 罚息金额
        loanInfoCi.setPunishIntAmt(lgPenInter);
        //57 HANG_INT_BAL 挂息金额
        loanInfoCi.setHangIntBal(BigDecimal.ZERO);
        //查询罚息利率参数 获取客户最大罚息利率
        BigDecimal penaltyRate = BigDecimal.ZERO;
        if (StringUtils.isNotBlank(loanInfoCi.getPunishIntIntRate())) {
            PrPenaltyRateTable prPenaltyRateTable = prPenaltyRateTableService.findByPenaltyId(loanInfoCi.getPunishIntIntRate(), org.getOrganizationId(), tenantId);
            BigDecimal currTate = BigDecimal.ZERO;
            if (ReportingConstant.INCREASE_TYPE_0.equals(prPenaltyRateTable.getIncreaseType())) {
                currTate = prPenaltyRateTable.getIncreaseNum();
            } else if (ReportingConstant.INCREASE_TYPE_1.equals(prPenaltyRateTable.getIncreaseType())) {
                currTate = actualDailyRate.multiply(new BigDecimal(1).add(prPenaltyRateTable.getIncreaseNum()));
            }
            if (penaltyRate.compareTo(currTate) < 0) {
                penaltyRate = currTate;
            }
        }
        //58 PUNISH_INT_INT_RATE 罚息利率
        loanInfoCi.setPunishIntIntRate(penaltyRate + "");
        //60 CURR_BAL 当期余额
        BigDecimal currBal = BigDecimal.ZERO;

        currBal = currBal.add(principal).add(ovdrPrincipal);
        loanInfoCi.setCurrBal(currBal);
        //61 CLCURR_CURR_BAL 折本币当期余额
        loanInfoCi.setClcurrCurrBal(currBal);
        //62 YEAR_INT_RATE 年利率
        loanInfoCi.setYearIntRate(countMain.getInterestRate() + "");
        //63 LON_DIR_CD 贷款投向行业代码
        //64 ORG_CONTRI_RATIO 机构出资比例
        //65 LON_TYPE_CD 贷款类型代码 消费贷-0200 经营贷-0300
        if (pro.getTableType().equals(ReportingConstant.LOAN_TYPE_6)) {
            loanInfoCi.setLonTypeCd("0300");
        } else {
            loanInfoCi.setLonTypeCd("0200");
        }

        // 扩展字段
        String extFields = mainInfo.getExtFields();
        // 收款信息
        if (StringUtils.isNotBlank(extFields)) {
            JSONObject jsonObject = JSONObject.parseObject(extFields);
            Object recverBankAcctNo = jsonObject.get("RECVER_BANK_ACCT_NO");
            Object recverAcctBank = jsonObject.get("RECVER_ACCT_BANK");
            Object recverName = jsonObject.get("RECVER_NAME");
            Object recverBankBankNo = jsonObject.get("RECVER_BANK_BANK_NO");
            Object recverBankFullname = jsonObject.get("RECVER_BANK_FULLNAME");
            //41 RECVER_BANK_ACCT_NO 收款人银行账号
            loanInfoCi.setRecverBankAcctNo(getString(recverBankAcctNo));
            //42 RECVER_ACCT_BANK 收款人账户银行
            loanInfoCi.setRecverAcctBank(getString(recverAcctBank));
            //43 RECVER_NAME 收款人名称
            loanInfoCi.setRecverName(getString(recverName));
            //66 RECVER_BANK_BANK_NO 收款人银行行号
            loanInfoCi.setRecverBankBankNo(getString(recverBankBankNo));
            //67 RECVER_BANK_FULLNAME 收款人银行全称
            loanInfoCi.setRecverBankFullname(getString(recverBankFullname));
        }

        //68 CURR_PROVIED_INT 当期已计提利息
        loanInfoCi.setCurrProviedInt(lgInter);
        //69 OFBS_OWE_INT_BAL 表外欠息余额
        loanInfoCi.setOfbsOweIntBal(ofbsOweIntBal);
        // 70 NTXE_REPAY_DT 下次还款日期
        //获取下期还款日 10号以前当月 10号以后下个月
        int curDD = Integer.parseInt(DateUtils.formatDate(busiDate).substring(9, 10));
        if (curDD >= 10) {
            paymentDate = DateUtils.getDateByMonth(paymentDate, 1);
        }
        loanInfoCi.setNtxeRepayDt(paymentDate);
        loanInfoCi.setTenantId(mainInfo.getTenantId());

        //获取上一日的贷款信息
        Calendar cal = Calendar.getInstance();
        cal.setTime(busiDate);
        cal.add(Calendar.DATE, -1);
        CmInteCoLonInfo lastCmInteCoLonInfo = extCmInteCoLonInfoMapper.selectByEtlDtAndDuBilNo(cal.getTime(), dubilNo, mainInfo.getTenantId());
        //73 MAX_DEBT 最大负债额
        BigDecimal maxBebt = BigDecimal.ZERO;
        maxBebt = maxBebt.add(principal).add(ovdrPrincipal);
        if (null != lastCmInteCoLonInfo && null != lastCmInteCoLonInfo.getMaxDebt()) {
            if (maxBebt.compareTo(lastCmInteCoLonInfo.getMaxDebt()) == 1) {
                loanInfoCi.setMaxDebt(maxBebt);
            } else {
                loanInfoCi.setMaxDebt(lastCmInteCoLonInfo.getMaxDebt());
            }
        } else {
            loanInfoCi.setMaxDebt(maxBebt);
        }
        /**
         * 25 PAID_TERM 已还期数
         * 除每月10日和13日外，其他日期每日取上一日的该值。
         * 每月10日和13日的批次，进行以下判断：
         * 本期账单金额大于0，且当前逾期状态为正常。
         * 若符合条件，则取上月10日和13日的已还期数+1。
         * 若不符合条件，则取上一日的已还期数。
         */
//        int currDD = Integer.parseInt(DateUtils.formatDate(busiDate).substring(9, 10));
//
//        CmInteCoLonInfo historyInfo = extCmInteCoLonInfoMapper.findByCustomerIdAndEtlDt(secondLevel.getCustomerId(), busiDate, secondLevel.getTenantId());
//        int paidTerm = 0;
//        if (Objects.nonNull(historyInfo) && (currDD == 10 || currDD == 13) && "1".equals(loanInfoCi.getLonStatusCd()) && BigDecimal.ZERO.compareTo(currBal) < 0) {
//            Date month = DateUtils.getMonthDays(busiDate, 1);
//            CmInteCoLonInfo newHistoryInfo = extCmInteCoLonInfoMapper.findByCustomerIdAndEtlDt(secondLevel.getCustomerId(), month, secondLevel.getTenantId());
//            paidTerm = Integer.parseInt(newHistoryInfo.getPaidTerm()) + 1;
//        } else if (Objects.nonNull(historyInfo)) {
//            paidTerm = Integer.parseInt(historyInfo.getPaidTerm());
//        }
//        loanInfoCi.setPaidTerm(paidTerm + "");
        return loanInfoCi;
    }

    /**
     * 转换还款类型
     *
     * @param paymentType
     * @param countAcct
     * @return
     */
    private String getRepayType(String paymentType, AmLoanAccountInfo countAcct) {

        if (ReportingConstant.REPAYMENT_TYPE_PREPAY_CURR.equals(paymentType) ||//提前还当期
                ReportingConstant.REPAYMENT_TYPE_PREPAY.equals(paymentType) ||//提前还款
                ReportingConstant.REPAYMENT_TYPE_PRETERMINTION.equals(paymentType) || //提前结清
                ReportingConstant.REPAYMENT_TYPE_BILLPREPAYCURR.equals(paymentType)//账单提前还当期
        ) {
            if (BigDecimal.ZERO.compareTo(countAcct.getCurrBalance()) < 0) {
                //提前还款
                return ReportingConstant.REPAYMENT_TYPE_PREPAY;
            }
            //提前结清
            return ReportingConstant.REPAYMENT_TYPE_PRETERMINTION;
        }
        //正常还款
        return ReportingConstant.REPAYMENT_TYPE_PAY;
    }

    /**
     * 修改贷款信息已还期数
     *
     * @param firstLevel
     * @return
     */
    @Override
    public CmInteCoLonRepayDtl modifyLoanInfo(CmCustomerFirstLevel firstLevel) {
        if (null == firstLevel) {
            logger.info("未获取到客户一级信息");
            return null;
        }
        String customerId = firstLevel.getCustomerId();
        if (Arrays.asList("150115","150117").contains(customerId)) {
            logger.info("该用户修数需绕过：{}", customerId);
            return null;
        }
        //兴安花系列产品
        List<String> xahSeriesProducts = BizTypeProducts.getXAHSeriesProducts();

        Date today = DateUtils.parseDate("2022-12-09");

        //查询客户当天还款流水
        List<TlPaymentLog> paymentLogList = extTlPaymentLogMapper.selectByCollateDateAndCustomerIdProducts(customerId,
                firstLevel.getTenantId(), today, ReportingConstant.PAYMENT_LOG_SUM_STATUS_S, xahSeriesProducts);
        if (CollectionUtils.isEmpty(paymentLogList)) {
            logger.info("未获取客户当日还款信息，客户编号: " + customerId);
            return null;
        }

        CmLimitChangeLog latestDateInfo = iCustomerLimitInfoService.queryLatestEtlEffectDate(firstLevel.getTenantId(), customerId, xahSeriesProducts);
        Date etlEffectiveDate = latestDateInfo.getEtlEffectiveDate();
        //统计客户订单信息
        AmLoanAccountInfo countAcct = extAmLoanAccountInfoMapper.selectMaxLoanWithProducts(customerId, firstLevel.getTenantId(), xahSeriesProducts, etlEffectiveDate);
        if (Objects.isNull(countAcct) || Objects.isNull(countAcct.getCurrBalance())) {
            logger.info("该用户{}数据有误，直接返回", customerId);
            return null;
        }
        AmLoanMainInfo countMain = extAmLoanMainInfoMapper.selectByCountCustomerWithProducts(customerId, firstLevel.getTenantId(), xahSeriesProducts, etlEffectiveDate);
        if (Objects.isNull(countMain) || Objects.isNull(countMain.getFirstPaymentDate())) {
            logger.info("该用户{}数据有误，直接返回", customerId);
            return null;
        }

        //当期结清标志
        String isClear = "是";
        //查询客户所有订单 -----兴安花系列产品的所有订单
        List<AmLoanAccountInfo> amLoanAccountInfoList = extAmLoanAccountInfoMapper.selectRemainPrincipalAllByLoanIdWithProducts(customerId,
                paymentLogList.get(0).getChannel(), firstLevel.getTenantId(), xahSeriesProducts);
        for (AmLoanAccountInfo info : amLoanAccountInfoList) {
            if (TransBizConstant.ACCOUNT_STATUS_2.equals(info.getAccountStatus())) {
                isClear = "否";
                break;
            }
        }

        //查询客户最大逾期天数 客户最大逾期天数
        int delqDays = 0;
        AmDelinquencyInfo amDelinquencyInfo = extAmDelinquencyInfoMapper.getMaxDelqDaysInfoWithProducts(customerId, firstLevel.getTenantId(), TransBizConstant.ACCOUNT_STATUS_1, xahSeriesProducts);
        if (null != amDelinquencyInfo) {
            delqDays = amDelinquencyInfo.getDelqDays();
        }

        //当期还款日
        Date currPaymentDate = getCurrPaymentDate(today);

        CmInteCoLonRepayDtl cmInteCoLonRepayDtl = new CmInteCoLonRepayDtl();
        //1 数据日期
        cmInteCoLonRepayDtl.setEtlDt(today);
        //2 法人机构标识
        cmInteCoLonRepayDtl.setLpOrgNo("XIB");
        //3 交易流水编号
        cmInteCoLonRepayDtl.setTxSeqNo(paymentLogList.get(0).getSeqNo());
        // 最早的一笔借据编号
        //用户是否已经有对应的综合额度信息

        CmLimitChangeLog changeLog = iCustomerLimitInfoService.queryFirstLimitChangeLog(firstLevel.getTenantId(), customerId, xahSeriesProducts);
        if (null == changeLog) {
            logger.info("没有查询到首次额度生效日期，客户id:{},机构id:{}", firstLevel.getTenantId(), customerId);
            return null;
        }
        //4 借据编号 客户最早的订单号
        cmInteCoLonRepayDtl.setDubilNo(changeLog.getEtlLoanId());
        //5 还款日期
        cmInteCoLonRepayDtl.setRepayDt(today);
        //6 还款时间
        cmInteCoLonRepayDtl.setRepayTime(DateUtils.format(paymentLogList.get(0).getCompleteTime(), DateUtils.DATETIME_PATTERN));
        //7 币种代码
        cmInteCoLonRepayDtl.setCurrCd("CNY");
        //8 当前还款期数

        int currRepayTerm = countingMonths(countMain.getFirstPaymentDate(), currPaymentDate);

        cmInteCoLonRepayDtl.setCurrRepayTerm(Long.valueOf(currRepayTerm));
        //9 本期延滞天数
        cmInteCoLonRepayDtl.setThTermDelayDays(Long.valueOf(delqDays));

        //计算还款本金利息罚息
        BigDecimal principalAmount = BigDecimal.ZERO;//本金
        BigDecimal interestAmount = BigDecimal.ZERO;//利息
        BigDecimal penaltyAmount = BigDecimal.ZERO;//罚息
        for (TlPaymentLog payLog : paymentLogList) {
            //根据流水查询还款分配表
            List<TlPaymentAllocationLog> allLogs = extTlPaymentAllocationLogMapper.selectBySeqNoAndTenantId(payLog.getSeqNo(), payLog.getTenantId());
            for (TlPaymentAllocationLog allocationLog : allLogs) {
                if (ReportingConstant.ACCOUNT_TYPE_06.equals(allocationLog.getConnectAccountType())) {
                    principalAmount = principalAmount.add(allocationLog.getPostingAmount());
                }
                if (ReportingConstant.ACCOUNT_TYPE_04.equals(allocationLog.getConnectAccountType())) {
                    interestAmount = interestAmount.add(allocationLog.getPostingAmount());
                }
                if (ReportingConstant.ACCOUNT_TYPE_11.equals(allocationLog.getConnectAccountType())) {
                    penaltyAmount = penaltyAmount.add(allocationLog.getPostingAmount());
                }
                if (ReportingConstant.ACCOUNT_TYPE_12.equals(allocationLog.getConnectAccountType())) {
                    penaltyAmount = penaltyAmount.add(allocationLog.getPostingAmount());
                }
            }
        }
        //10 本期实还本金
        cmInteCoLonRepayDtl.setThTermRepayPrin(principalAmount);
        //11 本期实还利息
        cmInteCoLonRepayDtl.setThTermRepayInt(interestAmount);
        //12 本期实还罚息
        cmInteCoLonRepayDtl.setThTermRepayPunishInt(penaltyAmount);
        //13 本期结清标志
        cmInteCoLonRepayDtl.setThTermPayoffMark(isClear);
        //14 来源平台编号
        cmInteCoLonRepayDtl.setSrcPlatNo("CCS");
        //15 REPAY_CLAIM_SITU_CD 索赔情况代码 TODO
        cmInteCoLonRepayDtl.setRepayClaimSituCd(" ");
        //16 REPAY_TYPE_CD	还款类型代码
        cmInteCoLonRepayDtl.setRepayTypeCd(getRepayType(paymentLogList, countAcct));
        cmInteCoLonRepayDtl.setTenantId(firstLevel.getTenantId());

        // '本期实还本金','本期实还利息', '本期实还罚息' 都大于0才需要供数（同时过滤只营销费的场景）
        if (principalAmount.compareTo(BigDecimal.ZERO) > 0 || interestAmount.compareTo(BigDecimal.ZERO) > 0 || penaltyAmount.compareTo(BigDecimal.ZERO) > 0) {
            return cmInteCoLonRepayDtl;
        }
        return null;
    }

    /**
     * 获取上一次已还期数
     *
     * @param coLonInfo
     * @param coLonInfoList
     */
    private void getLastPaidTerm(CmInteCoLonInfo coLonInfo, List<CmInteCoLonInfo> coLonInfoList) {
        // 预期取值为上一次的已还期数最大值
        OptionalInt max = coLonInfoList.stream().filter(l -> l.getEtlDt().compareTo(coLonInfo.getEtlDt()) < 0).map(CmInteCoLonInfo::getPaidTerm).mapToInt(num -> Integer.parseInt(num)).max();
        if (max.isPresent()) {
            coLonInfo.setPaidTerm(max.getAsInt() + "");
        } else {
            coLonInfo.setPaidTerm("0");
        }
    }

    /**
     * 根据条件查询客户扩展信息表
     *
     * @param channel
     * @param tenantId
     * @param customerId
     * @param productId
     */
    private CmCustomerExtInfo getUserExtendInfoConditions(String channel,String tenantId,String customerId,String productId) {
        // 根据条件查询客户扩展信息表
        CmCustomerExtInfo info = new CmCustomerExtInfo();
        info.setChannel(channel);
        info.setTenantId(tenantId);
        info.setCustomerId(customerId);
        info.setProductId(productId);
        CmCustomerExtInfo res = extCmCustomerExtInfoMapper.selectByConditions(info);
        return res;
    }

    /**
     * 兴安借 借款用途代码 -> 借款用途描述
     *
     * @param loanUseCd
     * @return
     */
    public static String getLonUsageName(String loanUseCd) {
        if (org.springframework.util.StringUtils.isEmpty(loanUseCd)){
            return TransBizConstant.LOAN_USE_DESC_A99;//其他
        }
        switch (loanUseCd) {
            //购买大额耐用消费品
            case TransBizConstant.XAJ_LOAN_USE_A100:
                return TransBizConstant.LOAN_USE_DESC_A0;
            //房屋装修
            case TransBizConstant.XAJ_LOAN_USE_A5:
                return TransBizConstant.LOAN_USE_DESC_A5;
            //旅游
            case TransBizConstant.XAJ_LOAN_USE_A9:
                return TransBizConstant.LOAN_USE_DESC_A9;
            //购置汽车
            case TransBizConstant.XAJ_LOAN_USE_A3:
                return TransBizConstant.LOAN_USE_DESC_A3;
            //购置车位
            case TransBizConstant.XAJ_LOAN_USE_A4:
                return TransBizConstant.LOAN_USE_DESC_A4;
            //婚庆育儿
            case TransBizConstant.XAJ_LOAN_USE_A6:
                return TransBizConstant.LOAN_USE_DESC_A6;
            //教育
            case TransBizConstant.XAJ_LOAN_USE_A13:
                return TransBizConstant.LOAN_USE_DESC_A13;
            //其他个人综合消费
            case TransBizConstant.XAJ_LOAN_USE_A99:
                return TransBizConstant.LOAN_USE_DESC_A99;
        }
        return TransBizConstant.LOAN_USE_DESC_A99;//其他 (默认)
    }

    /**
     * 兴安借api借款用途 -> 借款用途代码
     *
     * @param loanUseCd
     * @return
     */
    public static String getLoanUseCd(String loanUseCd) {
        if (org.springframework.util.StringUtils.isEmpty(loanUseCd)){
            return TransBizConstant.LOAN_USE_A99;//未知
        }
        switch (loanUseCd) {
            //购买大额耐用消费品
            case TransBizConstant.XAJ_LOAN_USE_A100:
                return TransBizConstant.LOAN_USE_A0;
            //房屋装修
            case TransBizConstant.XAJ_LOAN_USE_A5:
                return TransBizConstant.LOAN_USE_A5;
            //旅游
            case TransBizConstant.XAJ_LOAN_USE_A9:
                return TransBizConstant.LOAN_USE_A9;
            //购置汽车
            case TransBizConstant.XAJ_LOAN_USE_A3:
                return TransBizConstant.LOAN_USE_A3;
            //购置车位
            case TransBizConstant.XAJ_LOAN_USE_A4:
                return TransBizConstant.LOAN_USE_A4;
            //婚庆育儿
            case TransBizConstant.XAJ_LOAN_USE_A6:
                return TransBizConstant.LOAN_USE_A6;
            //教育
            case TransBizConstant.XAJ_LOAN_USE_A13:
                return TransBizConstant.LOAN_USE_A13;
            //其他个人综合消费
            case TransBizConstant.XAJ_LOAN_USE_A99:
                return TransBizConstant.LOAN_USE_A99;
        }
        return TransBizConstant.LOAN_USE_A99;//其他 (默认)
    }

    /**
     * 兴安借还款方式代码
     *
     * @param amortMethodTableId
     * @return
     */
    public static String getRepayWayCd(String amortMethodTableId) {
        if (org.springframework.util.StringUtils.isEmpty(amortMethodTableId)){
            return TransBizConstant.PRIN_CHARGE_OPTION_EPI;//(默认)02:等额本息
        }
        return amortMethodTableId;
    }

    /**
     * 兴安借还款方式名称
     *
     * @param amortMethodTableId
     * @return
     */
    public static String getRepayWayName(String amortMethodTableId) {
        if (org.springframework.util.StringUtils.isEmpty(amortMethodTableId)){
            return TransBizConstant.PRIN_CHARGE_OPTION_EPI_DESC;//(默认)等额本息
        }
        switch (amortMethodTableId) {
            //分期付款
            case TransBizConstant.PRIN_CHARGE_OPTION_EPEI:
                return TransBizConstant.PRIN_CHARGE_OPTION_EPEI_DESC;
            //等额本息
            case TransBizConstant.PRIN_CHARGE_OPTION_EPI:
                return TransBizConstant.PRIN_CHARGE_OPTION_EPI_DESC;
            //等额本金
            case TransBizConstant.PRIN_CHARGE_OPTION_EP:
                return TransBizConstant.PRIN_CHARGE_OPTION_EP_DESC;
            //按月付息，到期还本
            case TransBizConstant.PRIN_CHARGE_OPTION_MONTHLY_INTPAY:
                return TransBizConstant.PRIN_CHARGE_OPTION_MONTHLY_INTPAY_DESC;
            //按月付息，按年还本
            case TransBizConstant.PRIN_CHARGE_OPTION_MI_YP:
                return TransBizConstant.PRIN_CHARGE_OPTION_MI_YP_DESC;
            //利随本清
            case TransBizConstant.PRIN_CHARGE_OPTION_INTPAY:
                return TransBizConstant.PRIN_CHARGE_OPTION_INTPAY_DESC;
        }
        return TransBizConstant.PRIN_CHARGE_OPTION_EPI_DESC;//(默认)等额本息
    }
}
